commit d17f68e979fa6afa217092f64189a2ba31ed2b0f Author: ZhijuCen Date: Tue Jun 23 21:47:51 2026 +0800 Initial Commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7c0ce6e --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ + +.venv/ +__pycache__/ +*.log +.extract.log +html_cache/ diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..6324d40 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.14 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..858c57a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,87 @@ +# AGENTS.md — mql5-skills Project + +## Overview + +MQL5 Agent Skills project. Creates and publishes Agent Skills conforming to the +[AgentSkills.io Specification](https://agentskills.io/specification). + +- **Project version**: 0.1.0 (pinned during initial phase, not incremented per change) +- **SKILL.md version**: 0.1 (per-document, pinned during initial phase) +- **Language**: Python 3.14, uv-managed +- **Dependencies**: beautifulsoup4, requests + +## Directory Structure + +``` +mql5-skills/ +├── AGENTS.md # This file — project conventions +├── README.md # Public readme +├── pyproject.toml # uv project config +├── sitemaps/ # Source sitemaps from mql5.com +│ ├── sitemap_book_en.xml # 581 URLs → programming book +│ └── sitemap_docs_en.xml # 4135 URLs → API reference docs +├── html_cache/ # Downloaded HTML (lossless, gitignored) +│ ├── book/ # 581 .html files +│ └── docs/ # 4135 .html files +├── scripts/ # Extraction scripts (Python) +│ └── extract.py # Main extraction: XML → HTML → Markdown +├── skills/ +│ └── mql5/ # The MQL5 development skill +│ ├── SKILL.md # Skill definition (agentskills.io spec) +│ └── references/ +│ ├── book/ # Programming book markdown (from sitemap_book_en.xml) +│ │ ├── 0000-book.md +│ │ ├── 00-intro/ +│ │ │ ├── 0001-intro.md +│ │ │ └── pics/ +│ │ └── ... +│ └── docs/ # API reference markdown (from sitemap_docs_en.xml) +│ ├── 0000-docs.md +│ ├── 01-basis/ +│ │ ├── 0001-basis.md +│ │ └── pics/ +│ └── ... +└── docs-dev/ # Development documentation + ├── extraction.md # Extraction workflow and script design + ├── naming.md # Folder/file naming conventions + └── skill-design.md # SKILL.md content plan +``` + +## SKILL.md Convention (skills/mql5/) + +Per agentskills.io spec: +- Frontmatter: `name` (required, max 64 chars, lowercase+hyphens), `description` (required, max 1024 chars) +- Body: Markdown instructions for the agent +- Optional dirs: `scripts/`, `references/`, `assets/` +- Focus areas: positions, orders, indicators, ticks, bars + +## Extraction Workflow + +Two-phase pipeline (network only needed for Phase 1): + +``` +Phase 1: download — sitemap → fetch HTML → html_cache/ +Phase 2: convert — html_cache/ → parse HTML → download images → .md files +``` + +- Script: `scripts/extract.py` with `download`, `convert`, `debug` subcommands +- HTML cache: `html_cache/book/`, `html_cache/docs/` (lossless, gitignored) +- Output: `skills/mql5/references/book/`, `skills/mql5/references/docs/` +- Each sitemap URL → one .md file + corresponding .html in cache +- Images → `pics/` subfolder within chapter dir +- Debug target: TesterStatistics page (mixed content: tables, images, code, console output) + +## Naming Convention + +See `docs-dev/naming.md` for full specification. Key rules: +- 4-digit sequential prefix per file within a chapter folder +- 2-digit prefix on chapter folder names +- Chapter folder names derived from URL path segments +- Max one level of subfolder under `book/` or `docs/` +- Each chapter folder contains a `pics/` subfolder + +## Git Workflow + +- Conventional commits +- Do not commit .venv, __pycache__ +- Tag releases per semver diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/docs-dev/extraction.md b/docs-dev/extraction.md new file mode 100644 index 0000000..eb83150 --- /dev/null +++ b/docs-dev/extraction.md @@ -0,0 +1,150 @@ +# Extraction Workflow — Web Content to Markdown + +Two-phase pipeline: download HTML (lossless) → convert to Markdown (offline). + +``` +Phase 1: sitemap XML → URL list → fetch HTML → save to html_cache/ +Phase 2: html_cache/ HTML → parse → download images → write Markdown +``` + +- **Input**: `sitemaps/sitemap_book_en.xml`, `sitemaps/sitemap_docs_en.xml` +- **HTML cache**: `html_cache/book/`, `html_cache/docs/` +- **Output**: `skills/mql5/references/book/`, `skills/mql5/references/docs/` +- **Tool**: Python script using `requests` + `beautifulsoup4` + +## Script — `scripts/extract.py` + +### CLI + +```bash +# Phase 1: download HTML +python scripts/extract.py download --sitemap sitemaps/sitemap_book_en.xml +python scripts/extract.py download --all + +# Phase 2: convert to Markdown +python scripts/extract.py convert --sitemap sitemaps/sitemap_book_en.xml +python scripts/extract.py convert --all + +# Debug single page (fetches + analyzes) +python scripts/extract.py debug URL +``` + +Options (download/convert): +- `--sitemap PATH` — single sitemap +- `--all` — all known sitemaps +- `--force` — re-process everything (ignore progress log) +- `--dry-run` — show plan without processing + +### Phase 1 — Download + +1. Parse sitemap XML → URL list +2. Build file map (naming convention, see `naming.md`) +3. For each URL: + - Skip if already cached (idempotent) + - Fetch HTML with retry + rate limiting (0.5s delay) + - Save raw HTML to `html_cache/{label}/{NN-chapter}/{NNNN-name}.html` +4. Progress: `html_cache/{label}/.download.log` + +HTML files are saved as-is — no parsing, no transformation. + +### Phase 2 — Convert + +1. Parse sitemap XML → URL list (same mapping) +2. For each URL: + - Skip if already converted (idempotent) + - Read local HTML from `html_cache/` + - Parse `#help` content → elements + - Convert elements to Markdown + - Download images to `pics/` subfolder + - Write `.md` file +3. Progress: `{output_dir}/.convert.log` + +### HTML Cache Structure + +``` +html_cache/ +├── book/ +│ ├── 0000-book.html +│ ├── .download.log +│ ├── 00-intro/ +│ │ ├── 0001-intro.html +│ │ ├── 0002-intro-edit-compile-run.html +│ │ └── ... +│ └── ... +└── docs/ + ├── 0000-docs.html + ├── .download.log + ├── 00-basis/ + │ ├── 0001-basis.html + │ └── ... + └── ... +``` + +Filenames mirror the markdown output (same 4-digit prefix, same derived name). + +## Content Extraction Rules + +### Main Content Selector + +```css +#help > h1:nth-child(1) +``` + +Extract from this `

` through to the last content element. + +**Fallback**: If no `h1` exists (e.g. root pages like `/en/book`), use the +first `` child of `#help` as the start element. + +### Table Handling + +| Has `` | Meaning | Render as | +|---------------|---------|-----------| +| Yes | Data table with headers | Markdown table with `|---|` separator | +| No | Code block or console output | Fenced code block (` ``` `) | + +Tables without `` on mql5.com typically contain: +- MQL5 code (with `` color classes for syntax highlighting) +- MetaTrader 5 Strategy Tester console output + +### Image Handling + +The `` is often nested inside `

`. + +**Alt text extraction**: +1. Try `img.find_next_sibling("p")` +2. If not found, try `img.parent.find_next_sibling("p")` +3. Fall back to `img.get("alt", "")` + +**`

` containing ``**: The `

` is treated as an image block — +the `` is routed through the image download path. + +### Code Blocks + +- `

` → fenced code block with language detection
+- Language detected from CSS classes (`mql`, `cpp`, `sql`, etc.)
+- Text whitespace preserved (no space-joining)
+
+## Debug Target — TesterStatistics
+
+URL: `https://www.mql5.com/en/book/automation/tester/tester_testerstatistics`
+
+Content boundaries:
+- Start: `#help > h1:nth-child(1)` → "Getting testing financial statistics: TesterStatistics"
+- End: `p.p_Text:nth-child(45)`
+
+Exercises: data tables (thead), code blocks (no thead), images, console output.
+
+## Error Handling
+
+| Error | Phase 1 | Phase 2 |
+|-------|---------|---------|
+| HTTP 404 | Skip, log, continue | N/A (offline) |
+| HTTP 429/5xx | Retry with backoff | N/A |
+| Missing HTML | N/A | Log warning, skip |
+| Parse error | N/A | Log error, skip |
+| Image download fail | N/A | Log warning, use original URL |
+
+## Resumability
+
+Each phase has its own progress log. Re-running skips completed items.
+Use `--force` to re-process everything.
diff --git a/docs-dev/naming.md b/docs-dev/naming.md
new file mode 100644
index 0000000..9523c29
--- /dev/null
+++ b/docs-dev/naming.md
@@ -0,0 +1,147 @@
+# Naming Convention — Folder & File Structure
+
+This document specifies how sitemap URLs map to the file tree under
+`skills/mql5/references/book/` and `skills/mql5/references/docs/`.
+
+## Core Rules
+
+1. **One subfolder level**: Under `book/` or `docs/`, at most one level of
+   subfolder (the "chapter folder") is used. All pages within that chapter are
+   `.md` files directly inside the chapter folder.
+
+2. **`pics/` exception**: Each chapter folder may contain a `pics/` subfolder
+   for images extracted from that chapter's pages.
+
+3. **Sequential numbering**: Both chapter folders and files carry numeric
+   prefixes that reflect their order in the source sitemap.
+
+## Chapter Folders
+
+A "chapter" corresponds to the **first URL path segment** after the sitemap root.
+
+| Source URL pattern           | Chapter folder     |
+|------------------------------|--------------------|
+| `/en/book/intro` ...         | `00-intro/`        |
+| `/en/book/basis` ...         | `01-basis/`        |
+| `/en/docs/basis` ...         | `00-basis/`        |
+| `/en/docs/standardlibrary` … | `34-standardlibrary/` |
+
+- **Prefix**: 2-digit zero-padded number (00, 01, 02, …)
+- **Suffix**: the URL path segment (e.g. `intro`, `basis`, `standardlibrary`)
+- **Order**: by first occurrence in the sitemap
+
+Chapters are numbered **globally** within each sitemap (book and docs are
+independent numbering spaces).
+
+## Files Within a Chapter
+
+Each URL that belongs to a chapter becomes one `.md` file inside the chapter
+folder. The filename encodes:
+
+```
+{4-digit global number}-{derived-name}.md
+```
+
+- **4-digit prefix**: sequential number matching the URL's position in the
+  sitemap (0001, 0002, …). This is **global** across the entire sitemap, not
+  reset per chapter.
+- **Derived name**: the URL path **after** the depth-1 segment, with `/`
+  replaced by `-`. If the URL **is** the depth-1 segment itself (the chapter
+  index page), the name is the segment name.
+
+### Derived-name rules
+
+| URL path (after `/en/{book|docs}/`) | Chapter folder | File name           |
+|-------------------------------------|----------------|---------------------|
+| `intro`                             | `00-intro/`    | `0001-intro.md`     |
+| `intro/edit_compile_run`            | `00-intro/`    | `0002-edit-compile-run.md` |
+| `basis`                             | `01-basis/`    | `0015-basis.md`     |
+| `basis/syntax`                      | `01-basis/`    | `0016-basis-syntax.md` |
+| `basis/types/integer/integertypes`  | `01-basis/`    | `0019-basis-types-integer-integertypes.md` |
+| `standardlibrary/mathematics/...`   | `34-standardlibrary/` | `1143-standardlibrary-mathematics-....md` |
+
+### Root-level URLs
+
+The very first URL in each sitemap (e.g. `https://www.mql5.com/en/book` or
+`https://www.mql5.com/en/docs`) has no depth-1 segment. It is placed directly
+under the references root as:
+
+```
+0000-book.md      (for book sitemap)
+0000-docs.md      (for docs sitemap)
+```
+
+## Complete Example — Book (first 20)
+
+```
+skills/mql5/references/book/
+├── 0000-book.md                              # /en/book
+├── 00-intro/
+│   ├── 0001-intro.md                         # /en/book/intro
+│   ├── 0002-edit-compile-run.md              # /en/book/intro/edit_compile_run
+│   ├── 0003-mql-wizard.md                    # /en/book/intro/mql_wizard
+│   ├── ...
+│   └── pics/
+├── 01-basis/
+│   ├── 0015-basis.md                         # /en/book/basis
+│   ├── 0016-basis-identifiers.md             # /en/book/basis/identifiers
+│   ├── 0017-basis-builtin-types.md           # /en/book/basis/builtin_types
+│   ├── 0018-basis-builtin-types-integer-numbers.md
+│   ├── ...
+│   └── pics/
+├── 02-oop/
+│   ├── ...
+│   └── pics/
+...
+```
+
+## Complete Example — Docs (first 20)
+
+```
+skills/mql5/references/docs/
+├── 0000-docs.md                              # /en/docs
+├── 00-basis/
+│   ├── 0001-basis.md                         # /en/docs/basis
+│   ├── 0002-basis-syntax.md                  # /en/docs/basis/syntax
+│   ├── 0003-basis-syntax-commentaries.md     # /en/docs/basis/syntax/commentaries
+│   ├── 0004-basis-syntax-identifiers.md
+│   ├── 0005-basis-syntax-reserved.md
+│   ├── 0006-basis-types.md
+│   ├── 0007-basis-types-integer.md
+│   ├── 0008-basis-types-integer-integertypes.md
+│   ├── ...
+│   └── pics/
+├── 01-constants/
+│   ├── ...
+│   └── pics/
+...
+```
+
+## Image Handling
+
+- Images are saved to `pics/` within the chapter folder where they appear.
+- Filenames: `{original-filename}` or `{derived-name}.png` if no useful name.
+- The Markdown reference uses a relative path: `![alt](pics/image.png)`.
+- Per extraction spec: the `` alt text is taken from the next sibling
+  `

` element's innerHTML, not duplicated. + +## Name Sanitization + +When converting URL segments to file/folder names: + +| Character | Replacement | +|-----------|-------------| +| `_` | `-` | +| `/` | `-` (within filename) | +| Uppercase | lowercase | +| Non-alphanumeric (except `-`) | removed | + +Example: `builtin_types` → `builtin-types`, `MQL_Wizard` → `mql-wizard`. + +## Validation + +A post-extraction script should verify: +1. Every sitemap URL has exactly one output file. +2. File numbers are sequential with no gaps. +3. No file exceeds the 4-digit range (max 9999 URLs per sitemap). +4. Chapter folder names match the expected pattern: `{NN}-{segment}`. diff --git a/docs-dev/skill-design.md b/docs-dev/skill-design.md new file mode 100644 index 0000000..b24fcac --- /dev/null +++ b/docs-dev/skill-design.md @@ -0,0 +1,114 @@ +# SKILL.md Design — skills/mql5 + +This document describes the content and structure of `skills/mql5/SKILL.md`, +conforming to the [AgentSkills.io Specification](https://agentskills.io/specification). + +## Frontmatter + +```yaml +--- +name: mql5 +description: > + MQL5 development skill for MetaTrader 5. Covers Expert Advisors, Indicators, + Scripts, and Services. Focus on positions, orders, indicators, ticks, and bars. + Includes programming book and API reference documentation. +version: "0.1" +license: MIT +compatibility: > + Target: MetaTrader 5 platform. Language: MQL5 (C++-like syntax). + File extensions: *.mq5 (source), *.mqh (headers). + References: mql5.com/en/book (programming), mql5.com/en/docs (API). +metadata: + project-version: "0.1.0" + sources: + book: sitemaps/sitemap_book_en.xml (581 URLs) + docs: sitemaps/sitemap_docs_en.xml (4135 URLs) + focus-areas: + - positions + - orders + - indicators + - ticks + - bars +--- +``` + +## Body Content Structure + +The body should be structured as follows: + +### 1. Overview + +Brief description of MQL5 and MetaTrader 5: +- MQL5 is the programming language for MetaTrader 5 +- Syntax similar to C++ +- File types: `.mq5` (source), `.mqh` (headers) +- Program types: Expert Advisors, Indicators, Scripts, Services + +### 2. Quick Reference — Key Operations + +Focus areas with concise API patterns: + +#### Positions +- `CTrade` class for position management +- `PositionGetSymbol()`, `PositionSelect()`, `PositionGetDouble()` +- `CTrade::PositionOpen()`, `CTrade::PositionClose()` + +#### Orders +- `CTrade::OrderSend()` for pending orders +- `ORDER_TYPE_BUY_LIMIT`, `ORDER_TYPE_SELL_LIMIT`, etc. +- `OrderGetTicket()`, `OrderSelect()` + +#### Indicators +- `iMA()`, `iRSI()`, `iMACD()`, `iBands()` — built-in indicators +- `CopyBuffer()` to read indicator values +- `IndicatorCreate()` for custom indicators + +#### Ticks +- `SymbolInfoTick()` — current tick data +- `MqlTick` structure: `bid`, `ask`, `last`, `volume`, `time` +- `OnTick()` handler for Expert Advisors + +#### Bars +- `Bars()`, `BarsCalculated()` — bar count +- `CopyOpen()`, `CopyHigh()`, `CopyLow()`, `CopyClose()`, `CopyVolume()` +- `CopyRates()`, `CopyTime()` +- `CTerminalInfo`, `CSymbolInfo` for symbol/bar info + +### 3. Program Types + +| Type | Purpose | Key Handler | +|------|---------|-------------| +| Expert Advisor | Automated trading | `OnTick()`, `OnInit()`, `OnDeinit()` | +| Indicator | Technical analysis | `OnCalculate()` | +| Script | One-shot execution | `OnStart()` | +| Service | Background task | `OnStart()`, `OnTimer()` | + +### 4. Common Patterns + +- Trade execution with error handling +- Indicator buffer management +- Timer-based operations +- Chart object manipulation +- File I/O for logging/data + +### 5. References + +Point to the extracted documentation: +- `references/book/` — Programming book (learning path) +- `references/docs/` — API reference (function/type lookup) + +### 6. Pitfalls & Best Practices + +- `RefreshRates()` before trading operations +- `NormalizeDouble()` for price comparisons +- Check `Retcode()` after trade operations +- Use `CTrade` class over raw `OrderSend()` +- Handle `OnTimer()` for periodic operations +- Test with Strategy Tester before live deployment + +## Implementation Notes + +- The SKILL.md should be concise (< 1024 chars for description, body can be longer) +- Body is loaded as context by AI agents — prioritize actionable patterns +- Reference files provide depth; SKILL.md provides the "what to do" +- Version 0.1: initial content, will expand as extraction completes diff --git a/jobs/250013-job.md b/jobs/250013-job.md new file mode 100644 index 0000000..b6bb3ef --- /dev/null +++ b/jobs/250013-job.md @@ -0,0 +1,27 @@ + +# MT5 XAUUSD Order Block and Liquidity Expert Advisor + +[Origin](https://www.mql5.com/en/job/250013) + +## Specification + +* Use the H4 timeframe to determine the main trend direction. +* Identify valid order blocks on the H1 timeframe. +* Identify liquidity zones and liquidity sweeps. +* Wait for M15 confirmation before opening a trade. +* Only take buy trades in bullish market conditions and sell trades in bearish market conditions. +* Risk a fixed percentage of account balance per trade (user adjustable). +* Automatically calculate lot size based on risk. +* Place Stop Loss below/above the order block. +* Place Take Profit at a minimum 1:2 risk-to-reward ratio. +* Allow only one trade per signal. +* Include settings that can be adjusted by the user. +* Send MT5 mobile notifications when trades are opened and closed. +* Work on MT5 and Exness accounts. + +## Deliverables + +* Compiled EA (.ex5) +* Source code (.mq5) +* Installation instructions +* Backtest results diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..d91d8f4 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,10 @@ +[project] +name = "mql5-skills" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.14" +dependencies = [ + "beautifulsoup4>=4.15.0", + "requests>=2.34.2", +] diff --git a/resources/random-user-agents.csv b/resources/random-user-agents.csv new file mode 100644 index 0000000..4898c5a --- /dev/null +++ b/resources/random-user-agents.csv @@ -0,0 +1,37 @@ +browser,profile,user_agent +"Safari 26.3","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.3 Safari/605.1.15" +"Firefox 148","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64; rv:148.0) Gecko/20100101 Firefox/148.0" +"Chrome 145","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36" +"Edge 144","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" +"Edge 143","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0" +"Firefox 146","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0" +"Chrome 143","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" +"Chrome 143","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" +"Firefox 147","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0" +"Edge 145","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0" +"Safari 26.2","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Safari/605.1.15" +"Firefox 147","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:147.0) Gecko/20100101 Firefox/147.0" +"Edge 143","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0" +"Chrome 143","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" +"Firefox 146","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:146.0) Gecko/20100101 Firefox/146.0" +"Edge 145","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0" +"Chrome 144","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36" +"Firefox 148","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0" +"Edge 144","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" +"Chrome 144","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36" +"Safari 26.0","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15" +"Firefox 146","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64; rv:146.0) Gecko/20100101 Firefox/146.0" +"Edge 143","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0" +"Chrome 145","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36" +"Edge 144","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" +"Chrome 145","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36" +"Firefox 147","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64; rv:147.0) Gecko/20100101 Firefox/147.0" +"Chrome 144","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36" +"Edge 145","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0" +"Firefox 148","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:148.0) Gecko/20100101 Firefox/148.0" +"Safari 26.2","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Safari/605.1.15" +"Chrome 143","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" +"Edge 144","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 Edg/144.0.0.0" +"Firefox 148","Desktop · macOS","Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:148.0) Gecko/20100101 Firefox/148.0" +"Chrome 144","Desktop · Linux","Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36" +"Firefox 146","Desktop · Windows","Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:146.0) Gecko/20100101 Firefox/146.0" \ No newline at end of file diff --git a/scripts/extract.py b/scripts/extract.py new file mode 100644 index 0000000..f9cec4a --- /dev/null +++ b/scripts/extract.py @@ -0,0 +1,974 @@ +#!/usr/bin/env python3 +""" +Two-phase MQL5 content extraction: download HTML → convert to Markdown. + +Phase 1 (download): Fetch all HTML from mql5.com, save losslessly to html_cache/ +Phase 2 (convert): Parse local HTML, download images, write Markdown files + +Usage: + # Phase 1: download all HTML + python scripts/extract.py download --sitemap sitemaps/sitemap_book_en.xml + python scripts/extract.py download --sitemap sitemaps/sitemap_docs_en.xml + python scripts/extract.py download --all + + # Phase 2: convert HTML → Markdown + python scripts/extract.py convert --sitemap sitemaps/sitemap_book_en.xml + python scripts/extract.py convert --sitemap sitemaps/sitemap_docs_en.xml + python scripts/extract.py convert --all + + # Debug single page (fetches + converts) + python scripts/extract.py debug URL +""" + +import argparse +import hashlib +import logging +import os +import random +import re +import time +import xml.etree.ElementTree as ET +from pathlib import Path +from urllib.parse import urlparse + +import requests +from bs4 import BeautifulSoup, NavigableString, PageElement, Tag + +# --------------------------------------------------------------------------- +# Constants +# --------------------------------------------------------------------------- + +USER_AGENTS = { + "firefox": "Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0", + "msedge": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 Edg/148.0.0.0", + "chromium": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36", +} +UA_KEYS = list(USER_AGENTS.keys()) +_NUM_UA = len(UA_KEYS) + + +def load_user_agents_csv(csv_path: str) -> None: + """Load User-Agent strings from a CSV file, replacing module-level UA pool. + + CSV must have a ``user_agent`` column. Each row becomes one entry; + keys are ``u0``, ``u1``, … in file order. + """ + global USER_AGENTS, UA_KEYS, _NUM_UA + import csv as _csv + + with open(csv_path, newline="", encoding="utf-8") as f: + reader = _csv.DictReader(f) + if "user_agent" not in (reader.fieldnames or []): + raise ValueError(f"CSV {csv_path} has no 'user_agent' column") + pool = {f"u{i}": row["user_agent"] for i, row in enumerate(reader)} + + if not pool: + raise ValueError(f"CSV {csv_path} contains no User-Agent rows") + + USER_AGENTS = pool + UA_KEYS = list(USER_AGENTS.keys()) + _NUM_UA = len(UA_KEYS) + log.info("Loaded %d User-Agents from %s", _NUM_UA, csv_path) + + +def get_user_agent(index: int | None = None) -> str: + """Return a User-Agent string. Deterministic by index, or random.""" + if index is not None: + return USER_AGENTS[UA_KEYS[index % _NUM_UA]] + return USER_AGENTS[random.choice(UA_KEYS)] + +REQUEST_DELAY = 0.9 # seconds between requests +MAX_RETRIES = 3 +RETRY_BACKOFF = 2 # exponential backoff multiplier + +SITEMAP_NS = {"s": "http://www.sitemaps.org/schemas/sitemap/0.9"} + +# CSS selector for main content start +CONTENT_START_SELECTOR = "#help > h1:nth-child(1)" + +# HTML cache root +HTML_CACHE_ROOT = Path("html_cache") + +# Mapping: sitemap path → (output md dir, label) +SITEMAP_DEFAULTS = { + "sitemaps/sitemap_book_en.xml": ( + "skills/mql5/references/book", + "book", + ), + "sitemaps/sitemap_docs_en.xml": ( + "skills/mql5/references/docs", + "docs", + ), +} + +# --------------------------------------------------------------------------- +# Logging +# --------------------------------------------------------------------------- + +log = logging.getLogger("extract") + + +# --------------------------------------------------------------------------- +# Sitemap parsing +# --------------------------------------------------------------------------- + + +def parse_sitemap(sitemap_path: str) -> list[str]: + """Extract URLs from a sitemap XML file, in document order.""" + tree = ET.parse(sitemap_path) + urls = [loc.text for loc in tree.findall(".//s:url/s:loc", SITEMAP_NS)] + log.info("Parsed %d URLs from %s", len(urls), sitemap_path) + return urls + + +# --------------------------------------------------------------------------- +# URL → file mapping (naming convention, shared by both phases) +# --------------------------------------------------------------------------- + + +def sanitize_name(name: str) -> str: + """Convert a URL segment to a safe file/folder name.""" + name = name.lower() + name = name.replace("_", "-") + name = re.sub(r"[^a-z0-9-]", "", name) + name = re.sub(r"-{2,}", "-", name) + name = name.strip("-") + return name + + +def derive_name_from_url(url: str, root_prefix: str) -> str: + """Given a full URL and the root prefix (e.g. '/en/book/'), + return the 'path tail' used for naming.""" + path = url + if path.startswith("http"): + parsed = urlparse(path) + path = parsed.path + + path_clean = path.strip("/") + prefix_clean = root_prefix.strip("/") + + if path_clean.lower() == prefix_clean.lower(): + return "" + if path_clean.lower().startswith(prefix_clean.lower() + "/"): + return path_clean[len(prefix_clean) + 1 :] + return path_clean + + +def build_file_map( + urls: list[str], root_prefix: str, output_dir: str, label: str +) -> list[dict]: + """Build the mapping from URL index → file path. + + Returns a list of dicts with keys: + url, index (0-based), file_path (.md), html_path (.html), + chapter_folder, filename + """ + html_cache_dir = HTML_CACHE_ROOT / label + file_map = [] + chapter_counter = 0 + chapter_map: dict[str, int] = {} + + for idx, url in enumerate(urls): + tail = derive_name_from_url(url, root_prefix) + parts = tail.split("/") if tail else [] + + if not parts: + # Root URL + base = f"{idx:04d}-{label}" + filename_md = f"{base}.md" + filename_html = f"{base}.html" + file_path = Path(output_dir) / filename_md + html_path = html_cache_dir / filename_html + chapter_folder = None + else: + depth1 = parts[0] + if depth1 not in chapter_map: + chapter_map[depth1] = chapter_counter + chapter_counter += 1 + ch_num = chapter_map[depth1] + chapter_folder = f"{ch_num:02d}-{sanitize_name(depth1)}" + + if len(parts) == 1: + derived = sanitize_name(depth1) + else: + derived = "-".join(sanitize_name(p) for p in parts) + + base = f"{idx:04d}-{derived}" + filename_md = f"{base}.md" + filename_html = f"{base}.html" + file_path = Path(output_dir) / chapter_folder / filename_md + html_path = html_cache_dir / chapter_folder / filename_html + + file_map.append( + { + "url": url, + "index": idx, + "file_path": str(file_path), + "html_path": str(html_path), + "chapter_folder": chapter_folder, + "filename": filename_md, + } + ) + + log.info( + "Built file map: %d files, %d chapters", + len(file_map), + chapter_counter, + ) + return file_map + + +# --------------------------------------------------------------------------- +# Phase 1: Download HTML +# --------------------------------------------------------------------------- + + +def fetch_html(url: str, session: requests.Session) -> str | None: + """Fetch a URL with retry + backoff. Returns HTML text or None on failure.""" + for attempt in range(1, MAX_RETRIES + 1): + try: + resp = session.get(url, timeout=30) + if resp.status_code == 200: + return resp.text + if resp.status_code in (429, 500, 502, 503, 504): + wait = RETRY_BACKOFF**attempt + log.warning( + "HTTP %d for %s, retry %d/%d in %ds", + resp.status_code, url, attempt, MAX_RETRIES, wait, + ) + time.sleep(wait) + continue + log.error("HTTP %d for %s — skipping", resp.status_code, url) + return None + except requests.RequestException as exc: + wait = RETRY_BACKOFF**attempt + log.warning( + "Request error for %s: %s, retry %d/%d in %ds", + url, exc, attempt, MAX_RETRIES, wait, + ) + time.sleep(wait) + log.error("All %d retries failed for %s", MAX_RETRIES, url) + return None + + +def download_one(url: str, html_path: str, session: requests.Session) -> bool: + """Download a single URL and save to html_path. Returns True on success.""" + out = Path(html_path) + if out.exists(): + log.debug("Already cached: %s", html_path) + return True + + html = fetch_html(url, session) + if html is None: + return False + + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text(html, encoding="utf-8") + return True + + +def run_download( + sitemap_path: str, + force: bool = False, + dry_run: bool = False, + random_ua: bool = False, + random_delay: bool = False, + user_agents_csv: str | None = None, +) -> None: + """Phase 1: download all HTML files for a sitemap.""" + if user_agents_csv: + load_user_agents_csv(user_agents_csv) + urls = parse_sitemap(sitemap_path) + root_prefix = _root_prefix_from_sitemap(sitemap_path) + label = _label_from_sitemap(sitemap_path) + md_output_dir = SITEMAP_DEFAULTS.get(sitemap_path, ("", label))[0] + + file_map = build_file_map(urls, root_prefix, md_output_dir, label) + + if dry_run: + print(f"\n=== Download dry run: {sitemap_path} ===") + print(f"Total URLs: {len(file_map)}") + print(f"Cache dir: {HTML_CACHE_ROOT / label}") + for entry in file_map[:20]: + print(f" [{entry['index']:4d}] {entry['url']}") + print(f" → {entry['html_path']}") + if len(file_map) > 20: + print(f" ... ({len(file_map) - 20} more)") + return + + # Progress log + log_path = HTML_CACHE_ROOT / label / ".download.log" + processed = _load_log(log_path) if not force else set() + + session = requests.Session() + + success = 0 + skipped = 0 + failed = 0 + + for entry in file_map: + url = entry["url"] + if url in processed and not force: + skipped += 1 + continue + + session.headers.update({ + "User-Agent": get_user_agent() if random_ua else get_user_agent(entry["index"]) + }) + ok = download_one(url, entry["html_path"], session) + if ok: + success += 1 + _append_log(log_path, url) + log.info("[%d/%d] OK: %s", success + skipped + failed, len(file_map), url) + else: + failed += 1 + log.error("[%d/%d] FAIL: %s", success + skipped + failed, len(file_map), url) + + if random_delay: + time.sleep(REQUEST_DELAY * random.uniform(1.0, 3.0)) + else: + time.sleep(REQUEST_DELAY) + + log.info( + "Done: %d success, %d skipped, %d failed (total %d)", + success, skipped, failed, len(file_map), + ) + + +# --------------------------------------------------------------------------- +# Phase 2: Convert HTML → Markdown +# --------------------------------------------------------------------------- + +# Image downloading (only needed during convert phase) + + +def download_image( + img_url: str, pics_dir: Path, session: requests.Session +) -> str | None: + """Download an image, save to pics_dir, return local filename or None.""" + parsed = urlparse(img_url) + name = Path(parsed.path).name + if not name or "." not in name: + ext = ".png" + name = hashlib.md5(img_url.encode()).hexdigest()[:12] + ext + + local_path = pics_dir / name + if local_path.exists(): + return name + + try: + resp = session.get(img_url, timeout=30) + if resp.status_code == 200: + local_path.parent.mkdir(parents=True, exist_ok=True) + local_path.write_bytes(resp.content) + return name + except requests.RequestException as exc: + log.warning("Failed to download image %s: %s", img_url, exc) + return None + + +# HTML → Markdown conversion helpers + + +def get_text(el: Tag | NavigableString, sep: str = "") -> str: + """Recursively get text content.""" + if isinstance(el, NavigableString): + return str(el) + parts = [] + for child in el.children: + t = get_text(child, sep) + if t: + parts.append(t) + return sep.join(parts) + + +def inline_to_md(el: Tag) -> str: + """Convert an inline element to Markdown.""" + if isinstance(el, NavigableString): + return str(el) + + tag = el.name + inner = "".join(inline_to_md(c) for c in el.children) + + if tag in ("strong", "b"): + return f"**{inner}**" + if tag in ("em", "i"): + return f"*{inner}*" + if tag == "code": + if "`" in inner: + return f"`` {inner} ``" + return f"`{inner}`" + if tag == "a": + href = el.get("href", "") + if href and not href.startswith("#"): + return f"[{inner}]({href})" + return inner + if tag == "br": + return " \n" + if tag == "img": + src = el.get("src", "") + alt = el.get("alt", "") + return f"![{alt}]({src})" + if tag in ("span", "font", "u", "s", "sub", "sup", "small", "big", "mark"): + return inner + return inner + + +def table_to_md(table: Tag) -> str: + """Convert a to Markdown. + + Has → data table. No → code block. + """ + thead = table.find("thead") + tbody = table.find("tbody") or table + + if thead: + rows = [] + for tr in thead.find_all("tr"): + cells = [get_text(td, " ").strip() for td in tr.find_all(["th", "td"])] + rows.append(cells) + + ncols = max((len(r) for r in rows), default=0) + if rows and ncols: + rows.append(["---"] * ncols) + + body_rows = tbody.find_all("tr") if tbody else [] + for tr in body_rows: + if thead and tr.find_parent("thead"): + continue + cells = [get_text(td, " ").strip() for td in tr.find_all(["th", "td"])] + rows.append(cells) + + lines = [] + for row in rows: + while len(row) < ncols: + row.append("") + lines.append("| " + " | ".join(row) + " |") + return "\n".join(lines) + else: + code_lines = [] + all_rows = tbody.find_all("tr") if tbody else table.find_all("tr") + for tr in all_rows: + cells = tr.find_all(["td", "th"]) + for cell in cells: + code_el = cell.find("code") or cell.find("pre") + if code_el: + code_lines.append(get_text(code_el, "\n")) + else: + text = cell.get_text() + if text.strip(): + code_lines.append(text) + + code_text = "\n".join(code_lines) + lang = detect_code_lang(table) + return f"```{lang}\n{code_text}\n```" + + +def detect_code_lang(el: Tag) -> str: + """Try to detect code language from CSS classes.""" + classes = el.get("class", []) + if isinstance(classes, str): + classes = classes.split() + for cls in classes: + cl = cls.lower() + if "mql" in cl or "cpp" in cl or "c-plus" in cl: + return "cpp" + if "console" in cl or "output" in cl or "result" in cl: + return "" + if "sql" in cl: + return "sql" + parent = el.parent + if parent and isinstance(parent, Tag): + return detect_code_lang(parent) + return "" + + +def pre_to_md(pre: Tag) -> str: + """Convert
 to fenced Markdown code."""
+    code = pre.find("code")
+    if code:
+        lang = detect_code_lang(code)
+        text = get_text(code, "\n")
+    else:
+        lang = ""
+        text = get_text(pre, "\n")
+    return f"```{lang}\n{text}\n```"
+
+
+def element_to_md(
+    el: Tag,
+    pics_dir: Path | None,
+    session: requests.Session | None,
+    base_url: str,
+    img_cache: dict[str, str | None],
+) -> str:
+    """Convert a single content element to Markdown string."""
+    if isinstance(el, NavigableString):
+        text = str(el).strip()
+        return text if text else ""
+
+    tag = el.name
+
+    # --- Headings ---
+    if tag in ("h1", "h2", "h3", "h4", "h5", "h6"):
+        level = int(tag[1])
+        text = get_text(el, " ").strip()
+        return f"{'#' * level} {text}\n"
+
+    # --- Paragraphs ---
+    if tag == "p":
+        img_child = el.find("img")
+        if img_child:
+            return element_to_md(img_child, pics_dir, session, base_url, img_cache)
+        inner = "".join(inline_to_md(c) for c in el.children)
+        inner = inner.strip()
+        if not inner:
+            return ""
+        return f"{inner}\n"
+
+    # --- Images ---
+    if tag == "img":
+        src = el.get("src", "")
+        if not src:
+            return ""
+
+        if src.startswith("/"):
+            src = f"https://www.mql5.com{src}"
+        elif not src.startswith("http"):
+            src = f"{base_url.rstrip('/')}/{src}"
+
+        # Get alt text
+        alt_text = ""
+        next_sibling = el.find_next_sibling("p")
+        if not next_sibling and el.parent and isinstance(el.parent, Tag):
+            next_sibling = el.parent.find_next_sibling("p")
+        if next_sibling:
+            alt_text = get_text(next_sibling, " ").strip()
+        if not alt_text:
+            alt_text = el.get("alt", "")
+
+        # Download image
+        img_filename = None
+        if pics_dir and session:
+            if src in img_cache:
+                img_filename = img_cache[src]
+            else:
+                img_filename = download_image(src, pics_dir, session)
+                img_cache[src] = img_filename
+
+        if img_filename:
+            return f"![{alt_text}](pics/{img_filename})\n"
+        else:
+            return f"![{alt_text}]({src})\n"
+
+    # --- Tables ---
+    if tag == "table":
+        return table_to_md(el) + "\n"
+
+    # --- Preformatted code ---
+    if tag == "pre":
+        return pre_to_md(el) + "\n"
+
+    # --- Lists ---
+    if tag in ("ul", "ol"):
+        items = []
+        for i, li in enumerate(el.find_all("li", recursive=False)):
+            prefix = f"{i+1}. " if tag == "ol" else "- "
+            # If 
  • contains an , handle it through element_to_md + img_child = li.find("img") + if img_child: + img_md = element_to_md(img_child, pics_dir, session, base_url, img_cache) + # Get remaining text after the image + rest = "".join(inline_to_md(c) for c in li.children if not (isinstance(c, Tag) and c.name == "img")) + inner = (img_md.strip() + " " + rest.strip()).strip() + else: + inner = "".join(inline_to_md(c) for c in li.children) + items.append(f"{prefix}{inner.strip()}") + return "\n".join(items) + "\n" + + # --- Blockquote --- + if tag == "blockquote": + inner = get_text(el, " ").strip() + lines = inner.split("\n") + return "\n".join(f"> {line}" for line in lines) + "\n" + + # --- Horizontal rule --- + if tag == "hr": + return "---\n" + + # --- Code (standalone) --- + if tag == "code": + text = get_text(el, "\n") + return f"`{text}`\n" + + # --- Block containers: recurse --- + if tag in ("div", "section", "article", "figure", "figcaption", + "dl", "dd", "dt", "details", "summary", "main", "aside"): + parts = [] + for child in el.children: + if isinstance(child, NavigableString): + text = str(child).strip() + if text: + parts.append(text) + elif isinstance(child, Tag): + md = element_to_md(child, pics_dir, session, base_url, img_cache) + if md: + parts.append(md) + return "\n".join(parts) + + # --- Unknown tag --- + inner = "".join(inline_to_md(c) for c in el.children) + return inner.strip() if inner.strip() else "" + + +def extract_content(html: str, url: str) -> list[PageElement]: + """Parse HTML and extract the main content elements from #help.""" + soup = BeautifulSoup(html, "html.parser") + + help_div = soup.find(id="help") + if not help_div: + for sel in ("article", "main", ".article", "#article"): + help_div = soup.select_one(sel) + if help_div: + break + + if not help_div: + log.warning("No content container found for %s", url) + return [] + + start_el = help_div.select_one(CONTENT_START_SELECTOR) + if not start_el: + start_el = help_div.find("h1") + if not start_el: + for child in help_div.children: + if isinstance(child, Tag): + start_el = child + break + if not start_el: + log.warning("No content found in #help for %s", url) + return [] + + elements: list[PageElement] = [] + current: PageElement | None = start_el + while current: + elements.append(current) + current = current.find_next_sibling() + + return elements + + +def elements_to_markdown( + elements: list[PageElement], + pics_dir: Path | None, + session: requests.Session | None, + base_url: str, +) -> str: + """Convert a list of content elements to a Markdown string.""" + img_cache: dict[str, str | None] = {} + parts = [] + for el in elements: + md = element_to_md(el, pics_dir, session, base_url, img_cache) + if md: + parts.append(md) + + result = "\n".join(parts) + result = re.sub(r"\n{3,}", "\n\n", result) + return result.strip() + "\n" + + +# Phase 2: convert orchestrator + + +def convert_one( + html_path: str, + md_path: str, + pics_dir: Path | None, + session: requests.Session | None, + base_url: str, +) -> bool: + """Read a local HTML file and convert to Markdown. Returns True on success.""" + html_file = Path(html_path) + if not html_file.exists(): + log.warning("HTML cache miss: %s", html_path) + return False + + html = html_file.read_text(encoding="utf-8") + elements = extract_content(html, base_url) + if not elements: + log.warning("No content extracted from %s", html_path) + return False + + md_text = elements_to_markdown(elements, pics_dir, session, base_url) + + out = Path(md_path) + out.parent.mkdir(parents=True, exist_ok=True) + out.write_text(md_text, encoding="utf-8") + return True + + +def run_convert( + sitemap_path: str, + force: bool = False, + dry_run: bool = False, +) -> None: + """Phase 2: convert cached HTML to Markdown.""" + urls = parse_sitemap(sitemap_path) + root_prefix = _root_prefix_from_sitemap(sitemap_path) + label = _label_from_sitemap(sitemap_path) + md_output_dir = SITEMAP_DEFAULTS.get(sitemap_path, ("", label))[0] + + file_map = build_file_map(urls, root_prefix, md_output_dir, label) + + if dry_run: + print(f"\n=== Convert dry run: {sitemap_path} ===") + print(f"Total: {len(file_map)} files") + html_cache = HTML_CACHE_ROOT / label + cached = sum(1 for e in file_map if Path(e["html_path"]).exists()) + missing = len(file_map) - cached + print(f"Cached HTML: {cached}, Missing: {missing}") + for entry in file_map[:10]: + exists = Path(entry["html_path"]).exists() + mark = "✓" if exists else "✗" + print(f" [{entry['index']:4d}] {mark} {entry['html_path']}") + print(f" → {entry['file_path']}") + if len(file_map) > 10: + print(f" ... ({len(file_map) - 10} more)") + return + + # Progress log + log_path = Path(md_output_dir) / ".convert.log" + processed = _load_log(log_path) if not force else set() + + # Image session (only needed if images exist) + img_session: requests.Session | None = None + + success = 0 + skipped = 0 + failed = 0 + + for entry in file_map: + url = entry["url"] + if url in processed and not force: + skipped += 1 + continue + + pics_dir = None + if entry["chapter_folder"]: + pics_dir = Path(md_output_dir) / entry["chapter_folder"] / "pics" + + # Lazy-init image session only when needed + if img_session is None: + img_session = requests.Session() + + img_session.headers.update({"User-Agent": get_user_agent(entry["index"])}) + + base_url = url.rsplit("/", 1)[0] + "/" if "/" in url else url + ok = convert_one( + entry["html_path"], entry["file_path"], + pics_dir, img_session, base_url, + ) + if ok: + success += 1 + _append_log(log_path, url) + log.info("[%d/%d] OK: %s", success + skipped + failed, len(file_map), url) + else: + failed += 1 + log.error("[%d/%d] FAIL: %s", success + skipped + failed, len(file_map), url) + + log.info( + "Done: %d success, %d skipped, %d failed (total %d)", + success, skipped, failed, len(file_map), + ) + + +# --------------------------------------------------------------------------- +# Debug +# --------------------------------------------------------------------------- + + +def run_debug(url: str) -> None: + """Debug: fetch a single URL, print HTML structure, extract + convert.""" + session = requests.Session() + session.headers.update({"User-Agent": get_user_agent()}) + + print(f"Fetching: {url}") + html = fetch_html(url, session) + if html is None: + print("FETCH FAILED") + return + + soup = BeautifulSoup(html, "html.parser") + help_div = soup.find(id="help") + if not help_div: + print("#help NOT FOUND") + return + + print("#help found") + + h1 = help_div.select_one(CONTENT_START_SELECTOR) + if not h1: + h1 = help_div.find("h1") + if h1: + print(f"Start h1: {h1.get_text(strip=True)[:80]}") + + tables = help_div.find_all("table") + imgs = help_div.find_all("img") + pres = help_div.find_all("pre") + ps = help_div.find_all("p") + print(f"Tables: {len(tables)}, Imgs: {len(imgs)}, Pre: {len(pres)}, P: {len(ps)}") + + print("\n--- Tables ---") + for i, t in enumerate(tables): + thead = t.find("thead") + rows = t.find_all("tr") + first_cell = rows[0].find(["td", "th"]) if rows else None + cell_text = first_cell.get_text(strip=True)[:60] if first_cell else "(empty)" + has_code = bool(t.find("code") or t.find("pre")) + print(f" Table {i}: thead={bool(thead)}, rows={len(rows)}, " + f"code={has_code}, first: {cell_text}") + + print("\n--- Images ---") + for i, img in enumerate(imgs[:10]): + src = img.get("src", "") + alt = img.get("alt", "") + next_p = img.find_next_sibling("p") + next_p_text = next_p.get_text(strip=True)[:60] if next_p else "(no next p)" + print(f" Img {i}: src={src[:60]}, alt={alt[:40]}, next_p: {next_p_text}") + + print("\n--- Extraction ---") + elements = extract_content(html, url) + print(f"Extracted {len(elements)} elements") + + base_url = url.rsplit("/", 1)[0] + "/" if "/" in url else url + md_text = elements_to_markdown(elements, None, session, base_url) + print(f"\n--- Markdown output ({len(md_text)} chars) ---") + print(md_text[:3000]) + if len(md_text) > 3000: + print(f"\n... ({len(md_text) - 3000} more chars)") + + +# --------------------------------------------------------------------------- +# Progress log helpers +# --------------------------------------------------------------------------- + + +def _load_log(log_path: Path) -> set[str]: + """Load set of already-processed URLs from log file.""" + if not log_path.exists(): + return set() + urls = set() + for line in log_path.read_text().splitlines(): + line = line.strip() + if line and not line.startswith("#"): + urls.add(line) + return urls + + +def _append_log(log_path: Path, url: str) -> None: + """Append a URL to the processing log.""" + log_path.parent.mkdir(parents=True, exist_ok=True) + with open(log_path, "a") as f: + f.write(url + "\n") + + +# --------------------------------------------------------------------------- +# Sitemap helpers +# --------------------------------------------------------------------------- + + +def _root_prefix_from_sitemap(sitemap_path: str) -> str: + if "book" in sitemap_path: + return "/en/book/" + if "docs" in sitemap_path: + return "/en/docs/" + return "/" + + +def _label_from_sitemap(sitemap_path: str) -> str: + if "book" in sitemap_path: + return "book" + if "docs" in sitemap_path: + return "docs" + return "index" + + +# --------------------------------------------------------------------------- +# CLI +# --------------------------------------------------------------------------- + + +def main() -> None: + parser = argparse.ArgumentParser( + description="Two-phase MQL5 extraction: download HTML → convert to Markdown." + ) + sub = parser.add_subparsers(dest="command", required=True) + + # --- download --- + dl = sub.add_parser("download", help="Phase 1: download HTML from mql5.com") + dl_group = dl.add_mutually_exclusive_group(required=True) + dl_group.add_argument("--sitemap", help="Path to a sitemap XML file") + dl_group.add_argument("--all", action="store_true", help="All known sitemaps") + dl.add_argument("--force", action="store_true", help="Re-download all") + dl.add_argument("--dry-run", action="store_true", help="Show plan without fetching") + dl.add_argument("--random-ua", action="store_true", + help="Use random User-Agent per request (default: deterministic rotation)") + dl.add_argument("--random-delay", action="store_true", + help="Random delay between requests (1×–3× base delay)") + dl.add_argument("--user-agents-csv", metavar="CSV", + help="Import User-Agents from CSV file (must have 'user_agent' column)") + + # --- convert --- + cv = sub.add_parser("convert", help="Phase 2: convert cached HTML to Markdown") + cv_group = cv.add_mutually_exclusive_group(required=True) + cv_group.add_argument("--sitemap", help="Path to a sitemap XML file") + cv_group.add_argument("--all", action="store_true", help="All known sitemaps") + cv.add_argument("--force", action="store_true", help="Re-convert all") + cv.add_argument("--dry-run", action="store_true", help="Show plan without converting") + + # --- debug --- + dbg = sub.add_parser("debug", help="Debug: fetch + analyze a single URL") + dbg.add_argument("url", help="URL to debug") + + parser.add_argument("-v", "--verbose", action="store_true", help="Verbose logging") + + args = parser.parse_args() + + level = logging.DEBUG if args.verbose else logging.INFO + logging.basicConfig( + level=level, + format="%(asctime)s %(levelname)s %(message)s", + datefmt="%H:%M:%S", + ) + + if args.command == "debug": + run_debug(args.url) + return + + targets = [] + if args.command == "download": + if args.all: + targets = list(SITEMAP_DEFAULTS.keys()) + else: + targets = [args.sitemap] + for st in targets: + if not os.path.exists(st): + log.warning("Sitemap not found: %s — skipping", st) + continue + run_download(st, force=args.force, dry_run=args.dry_run, + random_ua=args.random_ua, random_delay=args.random_delay, + user_agents_csv=args.user_agents_csv) + + elif args.command == "convert": + if args.all: + targets = list(SITEMAP_DEFAULTS.keys()) + else: + targets = [args.sitemap] + for st in targets: + if not os.path.exists(st): + log.warning("Sitemap not found: %s — skipping", st) + continue + run_convert(st, force=args.force, dry_run=args.dry_run) + + +if __name__ == "__main__": + main() diff --git a/sitemaps/robots.txt b/sitemaps/robots.txt new file mode 100644 index 0000000..311f7bc --- /dev/null +++ b/sitemaps/robots.txt @@ -0,0 +1,116 @@ +Sitemap: https://www.mql5.com/sitemap.xml +Host: https://www.mql5.com + +User-agent: Mail.RU_Bot +Disallow: / + +User-agent: MJ12bot +Disallow: / + +User-agent: ExaBot +Disallow: / + +User-agent: CrazyWebCrawler-Spider +Disallow: / + +User-agent: SemrushBot +Disallow: / + +User-agent: AhrefsBot +Disallow: / + +User-agent: BLEXBot +Disallow: / + +User-agent: Yandex +Disallow: /*/search* +Disallow: /data* +Disallow: /return +Disallow: /drawtext +Disallow: /signals/charts/risks +Disallow: /*/signals/*/deals/page* +Disallow: /*/signals/*/pending-orders/page* +Disallow: /*/signals/*/positions/page* +Disallow: /*/signals/new +Disallow: /*/signals/*/news?skip= +Disallow: /*/signals/*/reviews +Disallow: /*/users/*/publications +Disallow: /*/users/*/achievements +Disallow: /*/users/*/feedbacks +Allow: /en/users/*/publications +Disallow: /*/messages/* +Disallow: /messages/avatar +Disallow: /*/channels/* +Disallow: /*/code/viewcode/* +Disallow: /go* +Disallow: /click* +Disallow: /*/auth_set +Disallow: /*/auth_forgotten +Disallow: /*/auth_forgot_confirm +Disallow: /*/publish/* +Disallow: /*_escaped_fragment_ +Disallow: /*?print= +Disallow: /p/ +Disallow: /captcha/ +Disallow: /*/accounting/buy/market/* +Disallow: /*/code/download/*/ +Disallow: /*/hosting/rules +Disallow: /maintenance.html +Disallow: /*/market/product/*/comments +Disallow: /*/market/product/*/updates +Disallow: /*/charts/* +Disallow: /*/quotes/charts/* +Disallow: /*/quotes/*/chart +Disallow: /en/quotes/*/chart +Allow: /*/book/applications/charts/ +Allow: /*/quotes/widgets/chart + +Clean-Param: v +Clean-Param: dir&orderby +Clean-Param: ref&count&Sort&sort +Clean-Param: utm_source&utm_medium&utm_campaign&utm_term&utm_content&utm_nooverride&utm_expid&gclid&_openstat&yclid&gsaid&source&ysclid&clickid&returnUrl& +Clean-Param: added&block&pos&device&etext&from +Clean-Param: filter&Filter + +User-agent: * +Disallow: /*/search* +Disallow: /data* +Disallow: /return +Disallow: /drawtext +Disallow: /signals/charts/risks +Disallow: /*/signals/*/deals/page* +Disallow: /*/signals/*/pending-orders/page* +Disallow: /*/signals/*/positions/page* +Disallow: /*/signals/new +Disallow: /*/signals/*/news?skip= +Disallow: /*/signals/*/reviews +Disallow: /*/users/*/publications +Disallow: /*/users/*/achievements +Disallow: /*/users/*/feedbacks +Allow: /en/users/*/publications +Disallow: /*/messages/* +Disallow: /messages/avatar +Disallow: /*/channels/* +Disallow: /*/code/viewcode/* +Disallow: /go* +Disallow: /click* +Disallow: /*/auth_set +Disallow: /*/auth_forgotten +Disallow: /*/auth_forgot_confirm +Disallow: /*/publish/* +Disallow: /*_escaped_fragment_ +Disallow: /*?print= +Disallow: /p/ +Disallow: /captcha/ +Disallow: /*/accounting/buy/market/* +Disallow: /*/code/download/*/ +Disallow: /*/hosting/rules +Disallow: /maintenance.html +Disallow: /*/market/product/*/comments +Disallow: /*/market/product/*/updates +Disallow: /*/charts/* +Disallow: /*/quotes/charts/* +Disallow: /*/quotes/*/chart +Disallow: /en/quotes/*/chart +Allow: /*/book/applications/charts/ +Allow: /*/quotes/widgets/chart \ No newline at end of file diff --git a/sitemaps/sitemap_book_en.xml b/sitemaps/sitemap_book_en.xml new file mode 100644 index 0000000..461a84d --- /dev/null +++ b/sitemaps/sitemap_book_en.xml @@ -0,0 +1,584 @@ + + +https://www.mql5.com/en/book2026-01-20T09:47:16+00:00weekly0.6 +https://www.mql5.com/en/book/intro2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/edit_compile_run2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/mql_wizard2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/statement_blocks2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/first_program2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/types_and_values2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/variables_and_identifiers2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/init_assign_express2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/data_input2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/errors_debug2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/a_data_output2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/b_formatting2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/intro/c_summing_up2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/identifiers2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/integer_numbers2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/float_numbers2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/characters2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/strings2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/booleans2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/datetime2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/colors2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/enums2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/user_enums2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/builtin_types/void2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/variables2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/variables/define_vs_declare2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/variables/scope_and_lifetime2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/variables/initialization2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/variables/static_variables2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/variables/const_variables2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/variables/input_variables2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/variables/variables_extern2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/arrays2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/arrays/arrays_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/arrays/arrays_declaration2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/arrays/arrays_usage2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/expressions_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operator_assignment2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operators_arithmetic2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/increment_decrement2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operators_relational2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operators_logical2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operators_bitwise2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operators_compound2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operator_conditional2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operator_comma2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operators_sizeof_typename2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operators_parentheses2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/expressions/operators_precedence2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/conversion2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/conversion/conversion_implicit2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/conversion/conversion_arithmetic2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/conversion/conversion_explicit2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_compound2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_declaration2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_expression2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_control2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_for2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_while2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_do2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_if2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_switch2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_break2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_continue2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_return2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/statements/statements_null2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_definition2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_call2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_parameters2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_ref_value2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_parameters_default2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_return2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_declaration2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_recursive2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_overloading2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_typedef2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/functions/functions_inline2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor/preprocessor_include2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor/preprocessor_define_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor/preprocessor_define_simple2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor/preprocessor_define_functional2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor/preprocessor_sharp2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor/preprocessor_undef2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor/preprocessor_predefined2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor/preprocessor_ifdefs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/basis/preprocessor/preprocessor_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/structs_and_unions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/structs_and_unions/structs_definition2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/structs_and_unions/structs_methods2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/structs_and_unions/structs_assignment2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/structs_and_unions/structs_ctor_dtor2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/structs_and_unions/structs_pack_dll2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/structs_and_unions/structs_composition2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/structs_and_unions/structs_access2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/structs_and_unions/unions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_abstraction2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_encapsulation2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_oop_inheritance2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_polymorphism2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_composition2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_definition2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_access_rights2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_ctors2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_dtors2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_this2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_inheritance2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_new_delete_pointers2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_pointers2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_virtual_override2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_static2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_namespace_context2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_declaration_definition2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_abstract_interfaces2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_operator_overloading2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_dynamic_cast_void2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_ref_pointers_const2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/classes_and_interfaces/classes_final_delete2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates/templates_header2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates/templates_principles2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates/templates_vs_macro2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates/templates_for_standard_and_object_types2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates/templates_functions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates/templates_objects2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates/templates_methods2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates/templates_nested2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/oop/templates/templates_specialization2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/conversions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/conversions/conversions_numbers2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/conversions/conversions_normalize2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/conversions/conversions_datetime2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/conversions/conversions_color2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/conversions/conversions_structs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/conversions/conversions_enums2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/conversions/conversions_complex2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/strings2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/strings/strings_init2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/strings/strings_concatenation2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/strings/strings_comparison2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/strings/strings_case_trim2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/strings/strings_find_replace_split2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/strings/strings_codepages2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/strings/strings_format2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays/arrays_print2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays/arrays_dynamic2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays/arrays_metrics2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays/arrays_init_fill2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays/arrays_edit2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays/arrays_move_swap2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays/arrays_compare_sort_search2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays/arrays_as_series2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/arrays/zero_memory2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_abs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_max_min2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_rounding2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_mod2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_pow_sqrt2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_exp_log2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_trig2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_hyper2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_nan2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_rand2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/maths/maths_byte_swap2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_modes_bin_txt2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_save_load2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_open_close2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_handles2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_txt_codepage2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_arrays2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_bin_structs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_bin_atomic2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_txt_atomic2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_cursor2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_flush2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_exist_delete2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_copy_move2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_find2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_folders2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/files/files_select2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/globals2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/globals/globals_set_get2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/globals/globals_exist_time2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/globals/globals_list2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/globals/globals_delete2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/globals/globals_temp2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/globals/globals_condition2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/globals/globals_flush2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/timing2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/timing/timing_local_server2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/timing/timing_daylight_saving2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/timing/timing_gmt2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/timing/timing_sleep2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/timing/timing_count2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/output2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/output/output_print2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/output/output_alert2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/output/output_comment2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/output/output_messagebox2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/output/output_sound2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_listing2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_build2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_type_license2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_mode2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_permissions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_connectivity2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_resources2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_screen2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_descriptive2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_bar_lang2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_signature2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_keyboard2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_stop2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_terminal_close2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_last_error2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_user_error2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_debug_break2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_variables2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/environment/env_constants2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_types2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_init2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_copy2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_copyrates2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_copyticks2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_expressions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_manipulations2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_mul2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_decomposition2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_stats2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_characteristics2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_sle2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/common/matrices/matrices_ml2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/runtime2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/runtime/runtime_features_by_progtype2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/runtime/runtime_threads2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/runtime/runtime_events_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/runtime/runtime_lifecycle2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/runtime/runtime_oninit_ondeinit2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/runtime/runtime_onstart2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/runtime/runtime_remove2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/script_service2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/script_service/scripts2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/script_service/services2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/script_service/script_service_limitations2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_symbol_period2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_storage_tech2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_bars2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_ibarshift2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_copy_funcs_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_mqlrates2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_ohlcvs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_single_value2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_highest_lowest2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timeseries/timeseries_ticks_mqltick2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_features2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_oncalculate2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_window_chart_separate2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_buffers_plots2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_setindexbuffer2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_plotindexsetinteger2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_buffer_to_plot_mapping2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_labels2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_empty_value2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_separate_window2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_caption_digits2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_color2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_begin2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_wait_none2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_multisymbol2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_newbars2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_test2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_limitations2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_make/indicators_wizard2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_descriptors2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_icustom2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_barscalculated2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_copybuffer2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_multitimeframe2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_standard2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_standard_use2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_indicatorcreate2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_flexible_create2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_chart_review2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_chart_plus_subwindow2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_shifted2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_indicatorrelease2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_parameters2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/indicators_use/indicators_apply_to2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timer2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timer/timer_event_set2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timer/timer_ontimer2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/timer/timer_event_set_millisecond2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_main_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_id2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_list2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_symbol_period2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_properties_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_string_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_window_state2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_count_visibility2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_mode2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_show_elements2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_shift2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_scale_time2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_scale_price2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_color2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_keyboard_mouse2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_floating2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_on_drop2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_coordinates2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_navigate2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_redraw2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_set_symbol_period2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_indicators2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_open_close2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_tpl2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/charts/charts_screenshot2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_main_characteristics2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_time_price2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_screen_coordinates2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_create2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_delete2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_find2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_properties_get_set2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_properties_main2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_time_price_coordinates2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_corner_x_y2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_anchor2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_state2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_z_order2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_color_style2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_font2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_angle2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_width_height2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_timeframes2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_arrow_codes2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_rays2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_pressed_state2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_bitmap2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_bitmap_offset2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_edit2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_stddev_channel2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_levels2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_gann_fibo_elliott2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_chart2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_move2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/objects/objects_get_time_value2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/events2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/events/events_onchartevent2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/events/events_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/events/events_chart2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/events/events_keyboard2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/events/events_mouse2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/events/events_objects2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/applications/events/events_custom2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_list2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_select2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_exist2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_sync2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_tick2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_sessions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_margin_rates2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_info2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_state2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_chart_mode2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_currencies2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_point_tick2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_volume2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_trade_mode2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_execution_filling2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_margin2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_expiration2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_spreads_levels2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_swaps2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_tick_parts2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_description2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_market_depth2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_custom2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/symbols/symbols_special2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/marketbook2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/marketbook/marketbook_add_release2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/marketbook/marketbook_events2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/marketbook/marketbook_get2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/marketbook/marketbook_application2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/account2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/account/account_info_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/account/account_number_identity2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/account/account_real_demo_contest2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/account/account_currency2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/account/account_netting_hedge2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/account/account_limits_and_restrictions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/account/account_margin2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/account/account_state2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_ontick2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_order_deal_position2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_request_types2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_order_type2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_execution_filling2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_pending_expiration2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_ordercalcmargin2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_ordercalcprofit2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_mqltraderequest2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_mqltradecheckresult2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_ordercheck2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_mqltraderesult2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_ordersend_ordersendasync2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_market_buy_sell2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_modify_position2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_trailing_stop2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_close2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_closeby2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_pending2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_modify_order2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_remove_order2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_order_list2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_order_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_orderget_funcs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_order_filter2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_position_list2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_position_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_positionget_funcs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_deal_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_history_select2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_historyorderget_funcs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_historydealget_funcs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_transaction_type2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_ontradetransaction2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_sync_vs_async2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_ontrade2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_trade_state2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_multisymbol2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_limitations2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/experts/experts_wizard2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_ticks2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_time2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_chart_limits2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_multicurrency_sync2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_criterion2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_testerstatistics2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_ontester2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_parameterrange2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_ontester_init_pass_deinit2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_frameadd2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_framenext2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_directives2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_testerhideindicators2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_withdraw_deposit2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_testerstop2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_example_ea2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_math_calc2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_debug_profile2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/automation/tester/tester_limitations2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_directive2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_sharing2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_variables2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_indicators2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_resourcecreate2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_resourcefree2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_resourcereadimage2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_resourcesave2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_textout2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/resources/resources_applied_usecase2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/custom_symbols2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/custom_symbols/custom_symbols_create_delete2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/custom_symbols/custom_symbols_properties2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/custom_symbols/custom_symbols_margin2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/custom_symbols/custom_symbols_sessions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/custom_symbols/custom_symbols_rates2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/custom_symbols/custom_symbols_ticks2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/custom_symbols/custom_symbols_market_book2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/custom_symbols/custom_symbols_trade_specifics2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_countries2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_event_kinds_by_country_currency2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_event_kind_by_id2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_records_by_country_currency2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_records_by_event_kind2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_record_by_id2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_change_last2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_change_last_by_event2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_filter_custom2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_cache_tester2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/calendar/calendar_trading2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/crypt2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/crypt/crypt_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/crypt/crypt_encode2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/crypt/crypt_decode2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_push2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_email2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_ftp2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_http2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_socket_create_connect2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_socket_state2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_socket_timeouts2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_socket_send_read2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_socket_tls_handshake_cert2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/network/network_socket_tls_send_read2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_intro2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_scheme_types2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_orm2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_db_create_open_close2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_simple_queries2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_table_exists2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_prepare2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_reset2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_bind2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_read2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_columns2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_crud_examples2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_transactions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_export_import2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_print2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/sqlite/sqlite_example_ts2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/libraries2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/libraries/libraries_export2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/libraries/libraries_import2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/libraries/libraries_path_lookup2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/libraries/libraries_dll2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/libraries/libraries_class_template2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/libraries/libraries_dotnet2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project/project_mqproj2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project/project_web_service_plan2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project/project_nodejs2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project/project_websockets2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project/project_websocket_server2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project/project_websocket_mql52026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project/project_echo_chat_mql52026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project/project_trade_signal_server2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/project/project_trade_signal_client_mql52026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_install2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_funcs_overview2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_init2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_last_error2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_account_info2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_terminal_info2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_symbols2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_marketbook2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_copyrates2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_copyticks2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_margin_profit2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_ordercheck_ordersend2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_orders2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_positions2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/python/python_history_deals2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/advanced/opencl2026-01-20T09:47:16+00:00monthly0.5 +https://www.mql5.com/en/book/conclusion2026-01-20T09:47:16+00:00monthly0.5 + \ No newline at end of file diff --git a/sitemaps/sitemap_docs_en.xml b/sitemaps/sitemap_docs_en.xml new file mode 100644 index 0000000..be659bd --- /dev/null +++ b/sitemaps/sitemap_docs_en.xml @@ -0,0 +1,4138 @@ + + +https://www.mql5.com/en/docs2026-06-22T09:20:25+00:00weekly0.6 +https://www.mql5.com/en/docs/basis2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/syntax2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/syntax/commentaries2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/syntax/identifiers2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/syntax/reserved2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/integer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/integer/integertypes2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/integer/symbolconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/integer/datetime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/integer/color2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/integer/boolconst2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/integer/enumeration2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/double2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/complex2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/stringconst2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/classes2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/dynamic_array2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/matrix_vector2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/casting2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/void2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/typedef2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/object_pointers2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/types/this2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operations/operexpression2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operations/mathoperation2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operations/assign2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operations/relation2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operations/bool2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operations/bit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operations/other2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operations/rules2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/compound2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/expression2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/return2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/if2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/ternary2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/switch2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/while2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/for2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/dowhile2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/break2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/continue2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/matmul2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/newoperator2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/operators/deleteoperator2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/function2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/function/call2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/function/parameterpass2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/function/functionoverload2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/function/operationoverload2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/function/extfunctions2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/function/export2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/function/events2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables/local2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables/formal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables/static2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables/global2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables/inputvariables2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables/externvariables2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables/initialization2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables/variable_scope2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/variables/object_live2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/preprosessor2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/preprosessor/constant2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/preprosessor/compilation2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/preprosessor/include2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/preprosessor/import2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/preprosessor/conditional_compilation2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop/incapsulation2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop/inheritance2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop/polymorphism2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop/overload2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop/virtual2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop/staticmembers2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop/templates2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop/class_templates2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/oop/abstract_type2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/basis/namespace2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/chartconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/chartconstants/enum_chartevents2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/chartconstants/enum_timeframes2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/chartconstants/enum_chart_property2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/chartconstants/enum_chart_position2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/chartconstants/chart_view2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/chartconstants/charts_samples2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_vline2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_hline2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_trend2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_trendbyangle2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_cycles2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrowed_line2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_channel2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_stddevchannel2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_regression2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_pitchfork2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_gannline2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_gannfan2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_ganngrid2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_fibo2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_fibotimes2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_fibofan2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_fiboarc2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_fibochannel2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_expansion2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_elliotwave52026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_elliotwave32026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_rectangle2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_triangle2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_ellipse2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_thumb_up2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_thumb_down2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_up2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_down2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_stop2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_check2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_left_price2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_right_price2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_buy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow_sell2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_arrow2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_text2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_label2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_button2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_chart2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_bitmap2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_bitmap_label2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_edit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_event2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object/obj_rectangle_label2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_object_property2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_anchorpoint2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_basecorner2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/visible2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_elliot_wave_degree2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/enum_gann_direction2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/webcolors2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/objectconstants/wingdings2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/indicatorconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/indicatorconstants/prices2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/indicatorconstants/enum_ma_method2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/indicatorconstants/lines2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/indicatorconstants/drawstyles2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/indicatorconstants/customindicatorproperties2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/indicatorconstants/enum_indicator2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/indicatorconstants/enum_datatype2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/environment_state2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/environment_state/terminalstatus2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/environment_state/mql5_programm_info2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/environment_state/marketinfoconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/environment_state/accountinformation2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/environment_state/statistics2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/tradingconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/tradingconstants/enum_series_info_integer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/tradingconstants/orderproperties2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/tradingconstants/positionproperties2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/tradingconstants/dealproperties2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/tradingconstants/enum_trade_request_actions2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/tradingconstants/enum_trade_transaction_type2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/tradingconstants/enum_book_type2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/tradingconstants/signalproperties2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/namedconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/namedconstants/compilemacros2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/namedconstants/mathsconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/namedconstants/typeconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/namedconstants/uninit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/namedconstants/enum_pointer_type2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/namedconstants/otherconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqldatetime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqlparam2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqlrates2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqlbookinfo2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqltraderequest2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqltradecheckresult2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqltraderesult2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqltradetransaction2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqltick2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/structures/mqlcalendar2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/errorswarnings2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/errorswarnings/enum_trade_return_codes2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/errorswarnings/warningscompile2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/errorswarnings/errorscompile2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/errorswarnings/errorcodes2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/io_constants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/io_constants/fileflags2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/io_constants/enum_file_property_integer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/io_constants/enum_file_position2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/io_constants/codepageusage2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constants/io_constants/messbconstants2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/runtime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/runtime/running2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/runtime/tradepermission2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/runtime/event_fire2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/runtime/resources2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/runtime/imports2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/runtime/errors2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/runtime/testing2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_appliedto2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_digits2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_point2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_lasterror2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_period2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_randomseed2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_stopflag2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_symbol2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_uninitreason2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/predefined/_isx642026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/alert2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/checkpointer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/comment2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/cryptencode2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/cryptdecode2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/debugbreak2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/expertremove2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/getpointer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/gettickcount2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/gettickcount642026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/getmicrosecondcount2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/messagebox2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/periodseconds2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/playsound2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/print2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/printformat2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/resetlasterror2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/resourcecreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/resourcefree2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/resourcereadimage2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/resourcesave2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/setreturnerror2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/setusererror2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/sleep2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/terminalclose2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/testerhideindicators2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/testerstatistics2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/testerstop2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/testerdeposit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/testerwithdrawal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/translatekey2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/common/zeromemory2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraybsearch2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraycopy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraycompare2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayfree2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraygetasseries2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayinitialize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayfill2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayisdynamic2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayisseries2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraymaximum2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayminimum2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayprint2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayrange2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayresize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayinsert2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayremove2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/array_reverse2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraysetasseries2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraysize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraysort2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayswap2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraytofp162026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arraytofp82026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayfromfp162026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/array/arrayfromfp82026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_types2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_types/matrix_enumerations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_assign2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_copyindicatorbuffer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_copyrates2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_copyticks2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_copyticksrange2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_eye2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_identity2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_ones2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_zeros2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_full2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_tri2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_init2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_fill2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_random2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_hasnan2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_replacenan2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_replacetozero2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_normalizedouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_transpose2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_transposeconjugate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_tril2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_triu2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_diag2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_row2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_col2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_copy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_conjugate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_concat2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_compare2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_comparebydigits2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/compareequal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_flat2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_clip2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_reshape2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_resize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_set2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_swaprows2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_swapcols2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_split2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_hsplit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_vsplit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_argsort2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_manipulations/matrix_sort2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_operations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_operations/matrix_math_operations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_operations/matrix_math_functions2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_matmul2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_gemm2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_power2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_dot2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_kron2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_inner2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_outer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_corrcoef2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_cov2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_correlate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_products/matrix_convolve2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_decompositions2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_decompositions/matrix_cholesky2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_decompositions/matrix_eig2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_decompositions/matrix_eigvals2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_decompositions/matrix_lu2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_decompositions/matrix_lup2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_decompositions/matrix_qr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_decompositions/matrix_svd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_argmax2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_argmin2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_max2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_min2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_ptp2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_sum2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_prod2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_cumsum2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_cumprod2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_percentile2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_quantile2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_median2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_mean2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_average2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_std2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_var2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_statistics/matrix_linearregression2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_rows2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_cols2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_size2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_norm2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_cond2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_det2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_slogdet2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_rank2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_trace2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_characteristics/matrix_spectrum2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_issymmetric2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_ishermitian2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_isuppertriangular2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_islowertriangular2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_istrapeziodal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_isupperhessenberg2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_islowerhessenberg2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_istridiagonal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_isupperbidiagonal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_islowerbidiagonal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_isdiagonal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_classification/matrix_isscalar2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_solves2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_solves/matrix_solve2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_solves/matrix_lstsq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_solves/matrix_inv2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_solves/matrix_pinv2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_activation2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_derivative2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_loss2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_lossgradient2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_regressionmetrics2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_confusionmatrix2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_confusionmatrixmultilabel2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_classificationmetric2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_classificationscore2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_precisionrecall2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/matrix_machine_learning/matrix_roc2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition/singularvaluedecompositiondc2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition/singularvaluedecompositionqr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition/singularvaluedecompositionqrp2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition/singularvaluedecompositionbise2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition/singularvaluedecompositionjh2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition/singularvaluedecompositionjl2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition/singularvaluedecompositiondddc2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition/singularvaluedecompositionbdbs2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/singular_value_decomposition/singularvaluedecompositionbdqr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigensolver2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigensolverx2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigensolverschur2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigensolver22026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigensolver2x2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigensolver2schur2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigensolver2blocked2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigensolver2schurblocked2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigenhessenbergschurq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigenvectorstriangularz2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/general_matrices/eigenvectorstriangularzblocked2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetricdc2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetricqr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetricrobust2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetricbisect2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetricdc2s2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetricqr2s2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetricrobust2s2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetricbisect2s2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetric2dc2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetric2qr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/symmetric_matrices/eigensymmetric2bisect2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/tridiagonalmatrices2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/tridiagonalmatrices/eigentridiagdc2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/tridiagonalmatrices/eigentridiagqr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/tridiagonalmatrices/eigentridiagrobust2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/tridiagonalmatrices/eigentridiagbisect2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/tridiagonalmatrices/eigentridiagql2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/tridiagonalmatrices/eigentridiagdcq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/tridiagonalmatrices/eigentridiagqrq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/eigen_values/tridiagonalmatrices/eigentridiagposdefq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations/linearequationssolution2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations/linearequationssolutiontriangl2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations/inversetriangular2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations/condnumreciprocaltriangular2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations/linearequationssolutionsy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations/linearequationssolutioncomplexsy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations/linearequationssolutionsypd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations/linearequationssolutiongetri2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/linear_equations/linearequationssolutionsytripd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/sylvester_equations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/sylvester_equations/sylvesterequation2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/sylvester_equations/sylvesterequationtriangular2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/sylvester_equations/sylvesterequationtriangular32026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/sylvester_equations/sylvesterequationschur2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/sylvester_equations/sylvesterequationschurblocked2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/least_squares2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/least_squares/leastsquaressolution2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/least_squares/leastsquaressolutiondc2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/least_squares/leastsquaressolutionsvd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/least_squares/leastsquaressolutionwy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/least_squares/leastsquaressolutionqrpivot2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/least_squares/leastsquaressolutionqrts2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationqr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationqrnonneg2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationqrpivot2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationqrtallskinny2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationlq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationlqshortwide2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationql2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationrq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationrz2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationqr22026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/orthogonal_factorizations/factorizationrq22026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationplu2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationpluq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationplugetrid2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationldl2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationldlcomplexsy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationldlsytridpd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationcholesky2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationcholeskysyps2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationpluraw2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationpluqraw2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationplugetridraw2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationldlraw2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factorizations/factorizationldlcomplexsyraw2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/plulinearequationssolution2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/pluinverse2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/plucondnumreciprocal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/pluqlinearequationssolution2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/plugetridlinearequations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/plugetridcondnumreciprocal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/ldllinearequationssolution2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/ldlinverse2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/ldlcondnumreciprocal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/ldlcomplexsylinearequationssolution2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/ldlcomplexsyinverse2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/ldlcomplexsycondnumreciprocal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/ldlsytridpdlinearequations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/ldlsytridpdcondnumreciprocal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/choleskylinearequations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/choleskyinverse2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/choleskycondnumreciprocal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/pseudo_inverse2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/factored_calculations/polar_decomposition2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/matrixtransforms2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/matrixtransforms/reducetobidiagonal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/matrixtransforms/reflectbidiagonaltoqp2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/matrixtransforms/reducesymmetrictotridiagonal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/matrixtransforms/reflecttridiagonaltoq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/matrixtransforms/reducetohessenberg2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/matrixtransforms/reflecthessenbergtoq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_norm2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_norm/matrixnormge2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_norm/matrixnormgetrid2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_norm/matrixnormhessenberg2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_norm/matrixnormsy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_norm/matrixnormcomplexsy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_norm/matrixnormsytrid2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_norm/matrixnormtriangular2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_balance2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_balance/matrixbalance2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_balance/eigenvectorsbackward2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_balance/reducetohessenbergbalanced2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_balance/reflecthessenbergbalancedtoq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_matrix_balance/eigenhessenbergbalancedschurq2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/dynamic_mode_decomposition2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/dynamic_mode_decomposition/dynamicmodedecomposition2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/dynamic_mode_decomposition/dynamicmodedecompositionqr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/ssa2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/ssa/ssa_spe2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/ssa/ssa_for2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/ssa/ssa_com2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/ssa/ssa_rec2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/l1_trend_filter2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/l1_trend_filter/l1trendfilterlambdamax2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/l1_trend_filter/l1trendfilter2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level22026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2gemv2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2symv2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2hemv2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2trmv2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2ger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2gerc2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2syr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2her2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2syr22026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level2/blasl2her22026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level32026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level3/blasl3gemm2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level3/blasl3symm2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level3/blasl3hemm2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level3/blasl3trmm2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level3/blasl3syrk2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level3/blasl3herk2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level3/blasl3syr2k2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/matrix/openblas/blas_level3/blasl3her2k2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/chartostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/chararraytostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/chararraytostruct2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/structtochararray2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/colortoargb2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/colortoprgb2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/colortostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/doubletostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/enumtostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/integertostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/shorttostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/shortarraytostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/timetostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/normalizedouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/stringtochararray2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/stringtocolor2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/stringtodouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/stringtointeger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/stringtoshortarray2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/stringtotime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/convert/stringformat2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathabs2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/matharccos2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/matharcsin2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/matharctan2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/matharctan22026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathclassify2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathceil2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathcos2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathexp2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathfloor2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathlog2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathlog102026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathmax2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathmin2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathmod2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathpow2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathrand2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathround2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathsin2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathsqrt2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathsrand2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathtan2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathisvalidnumber2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathexpm12026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathlog1p2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/matharccosh2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/matharcsinh2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/matharctanh2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathcosh2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathsinh2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathtanh2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/math/mathswap2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/strings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringbufferlen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringcompare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringconcatenate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringfill2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringfind2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringgetcharacter2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringinit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringlen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringsetlength2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringreplace2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringreserve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringsetcharacter2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringsplit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringsubstr2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringtolower2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringtoupper2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringtrimleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/strings/stringtrimright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/dateandtime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/dateandtime/timecurrent2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/dateandtime/timetradeserver2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/dateandtime/timelocal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/dateandtime/timegmt2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/dateandtime/timedaylightsavings2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/dateandtime/timegmtoffset2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/dateandtime/timetostruct2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/dateandtime/structtotime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/account2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/account/accountinfodouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/account/accountinfointeger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/account/accountinfostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/getlasterror2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/isstopped2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/uninitializereason2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/terminalinfointeger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/terminalinfodouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/terminalinfostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/mqlinfointeger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/mqlinfostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/symbol2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/period2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/digits2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/check/point2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/onstart2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/oninit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/ondeinit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/ontick2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/oncalculate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/ontimer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/ontrade2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/ontradetransaction2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/onbookevent2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/onchartevent2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/ontester2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/ontesterinit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/ontesterdeinit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/event_handlers/ontesterpass2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolstotal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolexist2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolname2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolselect2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolissynchronized2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolinfodouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolinfointeger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolinfostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolinfomarginrate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolinfotick2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolinfosessionquote2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/symbolinfosessiontrade2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/marketbookadd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/marketbookrelease2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/marketinformation/marketbookget2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendarcountrybyid2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendareventbyid2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendarvaluebyid2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendarcountries2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendareventbycountry2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendareventbycurrency2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendarvaluehistorybyevent2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendarvaluehistory2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendarvaluelastbyevent2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/calendar/calendarvaluelast2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/bufferdirection2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/timeseries_access2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/series/seriesinfointeger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/series/bars2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/barscalculated2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/indicatorcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/indicatorparameters2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/indicatorrelease2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copybuffer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copyrates2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copyseries2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copytime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copyopen2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copyhigh2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copylow2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copyclose2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copytickvolume2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copyrealvolume2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copyspread2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copyticks2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/copyticksrange2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/ibars2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/ibarshift2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/iclose2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/ihigh2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/ihighest2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/ilow2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/ilowest2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/iopen2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/itime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/itickvolume2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/irealvolume2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/ivolume2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/series/ispread2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customsymbolcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customsymboldelete2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customsymbolsetinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customsymbolsetdouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customsymbolsetstring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customsymbolsetmarginrate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customsymbolsetsessionquote2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customsymbolsetsessiontrade2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customratesdelete2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customratesreplace2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customratesupdate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customticksadd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customticksdelete2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/customticksreplace2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customsymbols/custombookadd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartapplytemplate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartsavetemplate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartwindowfind2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/charttimepricetoxy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartxytotimeprice2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartopen2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartfirst2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartnext2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartclose2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartsymbol2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartperiod2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartredraw2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartsetdouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartsetinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartsetstring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartgetdouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartgetinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartgetstring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartnavigate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartid2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartindicatoradd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartindicatordelete2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartindicatorget2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartindicatorname2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartindicatorstotal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartwindowondropped2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartpriceondropped2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/charttimeondropped2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartxondropped2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartyondropped2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartsetsymbolperiod2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/chart_operations/chartscreenshot2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/trading2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/ordercalcmargin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/ordercalcprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/ordercheck2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/ordersend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/ordersendasync2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/positionstotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/positiongetsymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/positionselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/positionselectbyticket2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/positiongetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/positiongetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/positiongetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/positiongetticket2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/orderstotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/ordergetticket2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/orderselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/ordergetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/ordergetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/ordergetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historyselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historyselectbyposition2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historyorderselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historyorderstotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historyordergetticket2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historyordergetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historyordergetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historyordergetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historydealselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historydealstotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historydealgetticket2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historydealgetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historydealgetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/trading/historydealgetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalbasegetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalbasegetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalbasegetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalbaseselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalbasetotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalinfogetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalinfogetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalinfogetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalinfosetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalinfosetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalsubscribe2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/signals/signalunsubscribe2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/network2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/socketcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/socketclose2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/socketconnect2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/socketisconnected2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/socketisreadable2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/socketiswritable2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/sockettimeouts2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/socketread2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/socketsend2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/sockettlshandshake2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/sockettlscertificate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/sockettlsread2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/sockettlsreadavailable2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/sockettlssend2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/webrequest2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/sendftp2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/sendmail2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/network/sendnotification2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariablecheck2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariabletime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariabledel2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariableget2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariablename2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariableset2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariablesflush2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariabletemp2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariablesetoncondition2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariablesdeleteall2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/globals/globalvariablestotal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/fileselectdialog2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filefindfirst2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filefindnext2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filefindclose2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/fileisexist2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/fileopen2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/fileclose2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filecopy2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filedelete2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filemove2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/fileflush2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filegetinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/fileisending2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/fileislineending2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereadarray2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereadbool2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereaddatetime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereaddouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereadfloat2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereadinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereadlong2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereadnumber2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereadstring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filereadstruct2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/fileseek2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filesize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filetell2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filewrite2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filewritearray2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filewritedouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filewritefloat2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filewriteinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filewritelong2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filewritestring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filewritestruct2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/fileload2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/filesave2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/foldercreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/folderdelete2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/files/folderclean2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_none2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_line2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_section2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_histogram2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_histogram22026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_arrow2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_zigzag2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_filling2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_bars2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_candles2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_color_line2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_color_section2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_color_histogram2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_color_histogram22026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_color_arrow2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_color_zigzag2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_color_bars2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicators_examples/draw_color_candles2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/propertiesandfunctions2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/setindexbuffer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicatorsetdouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicatorsetinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/indicatorsetstring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/plotindexsetdouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/plotindexsetinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/plotindexsetstring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/customind/plotindexgetinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectname2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectdelete2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectdeleteall2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectfind2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectgettimebyvalue2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectgetvaluebytime2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectmove2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectstotal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectsetdouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectsetinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectsetstring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectgetdouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectgetinteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/objectgetstring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/textsetfont2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/textout2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/objects/textgetsize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iac2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iad2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iadx2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iadxwilder2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ialligator2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iama2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iao2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iatr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ibearspower2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ibands2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ibullspower2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/icci2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ichaikin2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/icustom2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/idema2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/idemarker2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ienvelopes2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iforce2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ifractals2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iframa2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/igator2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iichimoku2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ibwmfi2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/imomentum2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/imfi2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ima2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iosma2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/imacd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iobv2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/isar2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/irsi2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/irvi2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/istddev2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/istochastic2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/itema2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/itrix2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/iwpr2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ividya2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/indicators/ivolumes2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/optimization_frames2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/optimization_frames/framefirst2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/optimization_frames/framefilter2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/optimization_frames/framenext2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/optimization_frames/frameinputs2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/optimization_frames/frameadd2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/optimization_frames/parametergetrange2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/optimization_frames/parametersetrange2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/eventfunctions2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/eventfunctions/eventsetmillisecondtimer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/eventfunctions/eventsettimer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/eventfunctions/eventkilltimer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/eventfunctions/eventchartcustom2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clhandletype2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clgetinfointeger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clgetinfostring2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clcontextcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clcontextfree2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clgetdeviceinfo2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clprogramcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clprogramfree2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clkernelcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clkernelfree2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clsetkernelarg2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clsetkernelargmem2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clsetkernelargmemlocal2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clbuffercreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clbufferfree2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clbufferwrite2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clbufferread2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clexecute2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/opencl/clexecutionstatus2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databaseopen2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databaseclose2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databaseimport2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databaseexport2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databaseprint2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasetableexists2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databaseexecute2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databaseprepare2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasereset2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasebind2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasebindarray2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databaseread2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasereadbind2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasefinalize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasetransactionbegin2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasetransactioncommit2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasetransactionrollback2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasecolumnscount2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasecolumnname2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasecolumntype2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasecolumnsize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasecolumntext2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasecolumninteger2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasecolumnlong2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasecolumndouble2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/database/databasecolumnblob2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxcontextcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxcontextsetsize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxcontextgetsize2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxcontextclearcolors2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxcontextcleardepth2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxcontextgetcolors2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxcontextgetdepth2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxbuffercreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxtexturecreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxinputcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxinputset2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxshadercreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxshadersetlayout2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxshaderinputsset2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxshadertexturesset2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxdraw2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxdrawindexed2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxprimivetopologyset2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxbufferset2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxshaderset2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxhandletype2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/directx/dxrelease2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader52026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5initialize_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5login_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5shutdown_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5version_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5lasterror_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5accountinfo_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5terminalinfo_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5symbolstotal_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5symbolsget_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5symbolinfo_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5symbolinfotick_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5symbolselect_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5marketbookadd_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5marketbookget_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5marketbookrelease_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5copyratesfrom_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5copyratesfrompos_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5copyratesrange_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5copyticksfrom_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5copyticksrange_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5orderstotal_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5ordersget_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5ordercalcmargin_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5ordercalcprofit_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5ordercheck_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5ordersend_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5positionstotal_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5positionsget_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5historyorderstotal_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5historyordersget_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5historydealstotal_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/python_metatrader5/mt5historydealsget_py2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnx_intro2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnx_conversion2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnx_types_autoconversion2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnx_prepare2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnx_mql52026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnx_test2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxcreate2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxcreatefrombuffer2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxrelease2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxrun2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxgetinputcount2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxgetoutputcount2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxgetinputname2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxgetoutputname2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxgetinputtypeinfo2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxgetoutputtypeinfo2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxsetinputshape2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnxsetoutputshape2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/onnx/onnx_structures2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/array_stat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/array_stat/mathmean2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/array_stat/mathvariance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/array_stat/mathskewness2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/array_stat/mathkurtosis2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/array_stat/mathmoments2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/array_stat/mathmedian2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/array_stat/mathstandarddeviation2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/array_stat/mathaveragedeviation2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/normal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/normal/mathprobabilitydensitynormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/normal/mathcumulativedistributionnormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/normal/mathquantilenormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/normal/mathrandomnormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/normal/mathmomentsnormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/lognormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/lognormal/mathprobabilitydensitylognormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/lognormal/mathcumulativedistributionlognormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/lognormal/mathquantilelognormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/lognormal/mathrandomlognormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/lognormal/mathmomentslognormal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/beta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/beta/mathprobabilitydensitybeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/beta/mathcumulativedistributionbeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/beta/mathquantilebeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/beta/mathrandombeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/beta/mathmomentsbeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralbeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralbeta/mathprobabilitydensitynoncentralbeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralbeta/mathcumulativedistributionnoncentralbeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralbeta/mathquantilenoncentralbeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralbeta/mathrandomnoncentralbeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralbeta/mathmomentsnoncentralbeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/gamma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/gamma/mathprobabilitydensitygamma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/gamma/mathcumulativedistributiongamma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/gamma/mathquantilegamma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/gamma/mathrandomgamma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/gamma/mathmomentsgamma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/chisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/chisquare/mathprobabilitydensitychisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/chisquare/mathcumulativedistributionchisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/chisquare/mathquantilechisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/chisquare/mathrandomchisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/chisquare/mathmomentschisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralchisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralchisquare/mathprobabilitydensitynoncentralchisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralchisquare/mathcumulativedistributionnoncentralchisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralchisquare/mathquantilenoncentralchisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralchisquare/mathrandomnoncentralchisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralchisquare/mathmomentsnoncentralchisquare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/exponential2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/exponential/mathprobabilitydensityexponential2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/exponential/mathcumulativedistributionexponential2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/exponential/mathquantileexponential2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/exponential/mathrandomexponential2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/exponential/mathmomentsexponential2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/fisher2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/fisher/mathprobabilitydensityf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/fisher/mathcumulativedistributionf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/fisher/mathquantilef2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/fisher/mathrandomf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/fisher/mathmomentsf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralfisher2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralfisher/mathprobabilitydensitynoncentralf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralfisher/mathcumulativedistributionnoncentralf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralfisher/mathquantilenoncentralf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralfisher/mathrandomnoncentralf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralfisher/mathmomentsnoncentralf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/student2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/student/mathprobabilitydensityt2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/student/mathcumulativedistributiont2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/student/mathquantilet2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/student/mathrandomt2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/student/mathmomentst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralstudent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralstudent/mathprobabilitydensitynoncentralt2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralstudent/mathcumulativedistributionnoncentralt2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralstudent/mathquantilenoncentralt2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralstudent/mathrandomnoncentralt2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/noncentralstudent/mathmomentsnoncentralt2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/logistic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/logistic/mathprobabilitydensitylogistic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/logistic/mathcumulativedistributionlogistic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/logistic/mathquantilelogistic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/logistic/mathrandomlogistic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/logistic/mathmomentslogistic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/cauchy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/cauchy/mathprobabilitydensitycauchy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/cauchy/mathcumulativedistributioncauchy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/cauchy/mathquantilecauchy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/cauchy/mathrandomcauchy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/cauchy/mathmomentscauchy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/unifrom2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/unifrom/mathprobabilitydensityuniform2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/unifrom/mathcumulativedistributionuniform2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/unifrom/mathquantileuniform2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/unifrom/mathrandomuniform2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/unifrom/mathmomentsuniform2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/weibull2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/weibull/mathprobabilitydensityweibull2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/weibull/mathcumulativedistributionweibull2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/weibull/mathquantileweibull2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/weibull/mathrandomweibull2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/weibull/mathmomentsweibull2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/binomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/binomial/mathprobabilitydensitybinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/binomial/mathcumulativedistributionbinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/binomial/mathquantilebinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/binomial/mathrandombinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/binomial/mathmomentsbinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/negativebinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/negativebinomial/mathprobabilitydensitynegativebinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/negativebinomial/mathcumulativedistributionnegativebinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/negativebinomial/mathquantilenegativebinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/negativebinomial/mathrandomnegativebinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/negativebinomial/mathmomentsmegativebinomial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/geometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/geometric/mathprobabilitydensitygeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/geometric/mathcumulativedistributiongeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/geometric/mathquantilegeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/geometric/mathrandomgeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/geometric/mathmomentsgeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/hypergeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/hypergeometric/mathprobabilitydensityhypergeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/hypergeometric/mathcumulativedistributionhypergeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/hypergeometric/mathquantilehypergeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/hypergeometric/mathrandomhypergeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/hypergeometric/mathmomentshypergeometric2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/poisson2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/poisson/mathprobabilitydensitypoisson2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/poisson/mathcumulativedistributionpoisson2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/poisson/mathquantilepoisson2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/poisson/mathrandompoisson2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/poisson/mathmomentspoisson2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathrandomnonzero2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathmoments2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathpowint2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathfactorial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathtrunc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathround2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmatharctan22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathgamma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathgammalog2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbeta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbetalog2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbetaincomplete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathgammaincomplete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbinomialcoefficient2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbinomialcoefficientlog2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathhypergeometric2f22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathsequence2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathsequencebycount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathreplicate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathreverse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathidentical2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathunique2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathquicksortascending2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathquicksortdescending2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathquicksort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathorder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbitwisenot2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbitwiseand2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbitwiseor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbitwisexor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbitwiseshiftl2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathbitwiseshiftr2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcumulativesum2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcumulativeproduct2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcumulativemin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcumulativemax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathsin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathtan2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmatharcsin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmatharccos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmatharctan2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathsinpi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcospi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathtanpi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathabs2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathceil2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathfloor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathsqrt2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathexp2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathpow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathlog2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathlog22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathlog102026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathlog1p2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathdifference2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathsample2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathtukeysummary2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathrange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathmin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathsum2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathproduct2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathstandarddeviation2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathaveragedeviation2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathmedian2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathmean2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathvariance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathskewness2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathkurtosis2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathexpm12026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathsinh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcosh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathtanh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmatharcsinh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmatharccosh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmatharctanh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathsignif2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathrank2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcorrelationpearson2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcorrelationspearman2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcorrelationkendall2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathquantile2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathprobabilitydensityempirical2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/stat/mathsubfunctions/statmathcumulativedistributionempirical2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cconstantmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cconstantmembershipfunction/cconstantmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ccompositemembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ccompositemembershipfunction/ccompositemembershipfunctioncompositiontype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ccompositemembershipfunction/ccompositemembershipfunctionmembershipfunctions2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ccompositemembershipfunction/ccompositemembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cdifferenctwosigmoidalmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cdifferenctwosigmoidalmembershipfunction/cdifferenctwosigmoidalmembershipfunctiona12026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cdifferenctwosigmoidalmembershipfunction/cdifferenctwosigmoidalmembershipfunctiona22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cdifferenctwosigmoidalmembershipfunction/cdifferenctwosigmoidalmembershipfunctionc12026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cdifferenctwosigmoidalmembershipfunction/cdifferenctwosigmoidalmembershipfunctionc22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cdifferenctwosigmoidalmembershipfunction/cdifferenctwosigmoidalmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cgeneralizedbellshapedmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cgeneralizedbellshapedmembershipfunction/cgeneralizedbellshapedmembershipfunctiona2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cgeneralizedbellshapedmembershipfunction/cgeneralizedbellshapedmembershipfunctionb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cgeneralizedbellshapedmembershipfunction/cgeneralizedbellshapedmembershipfunctionc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cgeneralizedbellshapedmembershipfunction/cgeneralizedbellshapedmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalcombinationmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalcombinationmembershipfunction/cnormalcombinationmembershipfunctionb12026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalcombinationmembershipfunction/cnormalcombinationmembershipfunctionb22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalcombinationmembershipfunction/cnormalcombinationmembershipfunctionsigma12026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalcombinationmembershipfunction/cnormalcombinationmembershipfunctionsigma22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalcombinationmembershipfunction/cnormalcombinationmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalmembershipfunction/cnormalmembershipfunctionb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalmembershipfunction/cnormalmembershipfunctionsigma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cnormalmembershipfunction/cnormalmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cp_shapedmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cp_shapedmembershipfunction/cp_shapedmembershipfunctiona2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cp_shapedmembershipfunction/cp_shapedmembershipfunctionb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cp_shapedmembershipfunction/cp_shapedmembershipfunctionc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cp_shapedmembershipfunction/cp_shapedmembershipfunctiond2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cp_shapedmembershipfunction/cp_shapedmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cproducttwosigmoidalmembershipfunctions2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cproducttwosigmoidalmembershipfunctions/cproducttwosigmoidalmembershipfunctionsa12026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cproducttwosigmoidalmembershipfunctions/cproducttwosigmoidalmembershipfunctionsa22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cproducttwosigmoidalmembershipfunctions/cproducttwosigmoidalmembershipfunctionsc12026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cproducttwosigmoidalmembershipfunctions/cproducttwosigmoidalmembershipfunctionsc22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cproducttwosigmoidalmembershipfunctions/cproducttwosigmoidalmembershipfunctionsgetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cs_shapedmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cs_shapedmembershipfunction/cs_shapedmembershipfunctiona2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cs_shapedmembershipfunction/cs_shapedmembershipfunctionb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cs_shapedmembershipfunction/cs_shapedmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/csigmoidalmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/csigmoidalmembershipfunction/csigmoidalmembershipfunctiona2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/csigmoidalmembershipfunction/csigmoidalmembershipfunctionc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/csigmoidalmembershipfunction/csigmoidalmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctrapezoidmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctrapezoidmembershipfunction/ctrapezoidmembershipfunctionx12026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctrapezoidmembershipfunction/ctrapezoidmembershipfunctionx22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctrapezoidmembershipfunction/ctrapezoidmembershipfunctionx32026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctrapezoidmembershipfunction/ctrapezoidmembershipfunctionx42026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctrapezoidmembershipfunction/ctrapezoidmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctriangularmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctriangularmembershipfunction/ctriangularmembershipfunctionx12026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctriangularmembershipfunction/ctriangularmembershipfunctionx22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctriangularmembershipfunction/ctriangularmembershipfunctionx32026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctriangularmembershipfunction/ctriangularmembershipfunctiontonormalmf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/ctriangularmembershipfunction/ctriangularmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cz_shapedmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cz_shapedmembershipfunction/cz_shapedmembershipfunctiona2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cz_shapedmembershipfunction/cz_shapedmembershipfunctionb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/cz_shapedmembershipfunction/cz_shapedmembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/imembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_membership/imembershipfunction/imembershipfunctiongetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cmamdanifuzzyrule2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cmamdanifuzzyrule/cmamdanifuzzyruleconclusion2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cmamdanifuzzyrule/cmamdanifuzzyruleweight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/csugenofuzzyrule2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/csugenofuzzyrule/csugenofuzzyruleconclusion2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/csinglecondition2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/csinglecondition/csingleconditionnot2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/csinglecondition/csingleconditionterm2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/csinglecondition/csingleconditionvar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cconditions2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cconditions/cconditionsconditionslist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cconditions/cconditionsnot2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cconditions/cconditionsop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cgenericfuzzyrule2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cgenericfuzzyrule/cgenericfuzzyruleconclusion2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cgenericfuzzyrule/cgenericfuzzyrulecondition2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_rule/cgenericfuzzyrule/cgenericfuzzyrulecreatecondition2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/cfuzzyvariable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/cfuzzyvariable/cfuzzyvariableaddterm2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/cfuzzyvariable/cfuzzyvariablegettermbyname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/cfuzzyvariable/cfuzzyvariablemax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/cfuzzyvariable/cfuzzyvariablemin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/cfuzzyvariable/cfuzzyvariableterms2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/cfuzzyvariable/cfuzzyvariablevalues2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/csugenovariable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/csugenovariable/csugenovariablefunctions2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/csugenovariable/csugenovariablegetfuncbyname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_variable/csugenovariable/csugenovariablevalues2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/cfuzzyterm2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/cfuzzyterm/cfuzzytermmembershipfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem/cmamdanifuzzysystemaggregationmethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem/cmamdanifuzzysystemcalculate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem/cmamdanifuzzysystemdefuzzificationmethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem/cmamdanifuzzysystememptyrule2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem/cmamdanifuzzysystemimplicationmethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem/cmamdanifuzzysystemoutput2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem/cmamdanifuzzysystemoutputbyname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem/cmamdanifuzzysystemparserule2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/cmamdanifuzzysystem/cmamdanifuzzysystemrules2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/csugenofuzzysystem2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/csugenofuzzysystem/csugenofuzzysystemcalculate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/csugenofuzzysystem/csugenofuzzysystemcreatesugenofunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/csugenofuzzysystem/csugenofuzzysystememptyrule2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/csugenofuzzysystem/csugenofuzzysystemoutput2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/csugenofuzzysystem/csugenofuzzysystemoutputbyname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/csugenofuzzysystem/csugenofuzzysystemparserule2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/mathematics/fuzzy_logic/fuzzy_system/csugenofuzzysystem/csugenofuzzysystemrules2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclbuffercreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclbufferfree2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclbufferfromarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclbufferread2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclbufferwrite2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclexecute2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclgetcontext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclgetkernel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclgetkernelname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclgetprogram2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclinitialize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclkernelcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclkernelfree2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclsetargument2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclsetargumentbuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclsetargumentlocalmemory2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclsetbufferscount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclsetkernelscount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclshutdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/copencl/copenclsupportdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cobject2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cobject/cobjectgetprev2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cobject/cobjectsetprev2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cobject/cobjectgetnext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cobject/cobjectsetnext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cobject/cobjectcompare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cobject/cobjectsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cobject/cobjectload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cobject/cobjecttype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carraystep2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carraystepbool2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carraytotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carrayavailable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carraymax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carrayissorted2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carraysortmode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carrayclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carraysort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carraysave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carray/carrayload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharreserve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharshutdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharaddarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharaddarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharinsertarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharinsertarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharassignarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharassignarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraychardelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraychardeleterange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharcomparearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharcomparearrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharinsertsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharsearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharsearchgreat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharsearchless2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharsearchgreatorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharsearchlessorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharsearchfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharsearchlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharsearchlinear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraycharload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraychar/carraychartype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortreserve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortshutdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortaddarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortaddarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortinsertarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortinsertarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortassignarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortassignarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortdeleterange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortcomparearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortcomparearrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortinsertsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortsearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortsearchgreat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortsearchless2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortsearchgreatorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortsearchlessorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortsearchfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortsearchlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortsearchlinear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshortload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayshort/carrayshorttype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintreserve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintshutdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintaddarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintaddarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintinsertarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintinsertarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintassignarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintassignarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintdeleterange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintcomparearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintcomparearrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintinsertsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintsearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintsearchgreat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintsearchless2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintsearchgreatorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintsearchlessorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintsearchfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintsearchlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintsearchlinear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayintload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayint/carrayinttype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongreserve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongshutdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongaddarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongaddarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylonginsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylonginsertarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylonginsertarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongassignarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongassignarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongdeleterange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongcomparearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongcomparearrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylonginsertsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongsearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongsearchgreat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongsearchless2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongsearchgreatorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongsearchlessorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongsearchfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongsearchlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongsearchlinear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraylong/carraylongtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatdelta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatreserve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatshutdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloataddarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloataddarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatinsertarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatinsertarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatassignarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatassignarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatdeleterange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatcomparearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatcomparearrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatinsertsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatsearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatsearchgreat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatsearchless2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatsearchgreatorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatsearchlessorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatsearchfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatsearchlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatsearchlinear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloatload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayfloat/carrayfloattype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubledelta2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublereserve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleshutdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleaddarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleaddarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleinsertarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleinsertarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleassignarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleassignarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubledelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubledeleterange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublecomparearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublecomparearrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleminimum2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublemaximum2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleinsertsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublesearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublesearchgreat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublesearchless2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublesearchgreatorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublesearchlessorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublesearchfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublesearchlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublesearchlinear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoublesave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubleload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraydouble/carraydoubletype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringreserve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringshutdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringaddarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringaddarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringinsertarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringinsertarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringassignarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringassignarrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringdeleterange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringcomparearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringcomparearrayconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringinsertsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringsearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringsearchgreat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringsearchless2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringsearchgreatorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringsearchlessorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringsearchfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringsearchlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringsearchlinear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carraystring/carraystringtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjfreemode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjfreemodeconst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjreserve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjshutdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjcreateelement2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjaddarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjinsertarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjassignarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjdetach2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjdeleterange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjcomparearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjinsertsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjsearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjsearchgreat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjsearchless2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjsearchgreatorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjsearchlessorequal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjsearchfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjsearchlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/carrayobj/carrayobjtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistfreemode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistfreemode22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clisttotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistissorted2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistsortmode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistcreateelement2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistdetachcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistdeletecurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistindexof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistgetnodeatindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistgetfirstnode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistgetprevnode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistgetcurrentnode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistgetnextnode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistgetlastnode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistmovetoindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistexchange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistcomparelist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistsearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clistload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/clist/clisttype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodeowner2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodeleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenoderight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodebalance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodebalancel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodebalancer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodecreatesample2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenoderefreshbalance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodegetnext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodesavenode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodeloadnode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctreenode/ctreenodetype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreeroot2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreecreateelement2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreeinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreedetach2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreedelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreeclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreefind2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreesave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreeload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/datastructures/ctree/ctreetype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icollection2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icollection/icollectionadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icollection/icollectioncount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icollection/icollectioncontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icollection/icollectioncopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icollection/icollectionclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icollection/icollectionremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iequalitycomparable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iequalitycomparable/iequalitycomparableequals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iequalitycomparable/iequalitycomparablehashcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icomparable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icomparable/icomparablecompare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icomparer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/icomparer/icomparercompare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iequalitycomparer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iequalitycomparer/iequalitycomparerequals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iequalitycomparer/iequalitycomparerhashcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ilist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ilist/ilisttrygetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ilist/ilisttrysetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ilist/ilistinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ilist/ilistindexof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ilist/ilistlastindexof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ilist/ilistremoveat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/imap2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/imap/imapadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/imap/imapcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/imap/imapremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/imap/imaptrygetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/imap/imaptrysetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/imap/imapcopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetexceptwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetintersectwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetsymmetricexceptwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetunionwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetispropersubsetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetispropersupersetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetissubsetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetissupersetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetoverlaps2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/iset/isetsetequals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cdefaultcomparer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cdefaultcomparer/cdefaultcomparercompare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cdefaultequalitycomparer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cdefaultequalitycomparer/cdefaultequalitycomparerequals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cdefaultequalitycomparer/cdefaultequalitycomparerhashcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktreenode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktreenode/credblacktreenodevalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktreenode/credblacktreenodeparent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktreenode/credblacktreenodeleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktreenode/credblacktreenoderight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktreenode/credblacktreenodecolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktreenode/credblacktreenodeisleaf2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktreenode/credblacktreenodecreateemptynode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlistnode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlistnode/clinkedlistnodelist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlistnode/clinkedlistnodenext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlistnode/clinkedlistnodeprevious2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlistnode/clinkedlistnodevalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ckeyvaluepair2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ckeyvaluepair/ckeyvaluepairkey2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ckeyvaluepair/ckeyvaluepairvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ckeyvaluepair/ckeyvaluepairclone2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ckeyvaluepair/ckeyvaluepaircompare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ckeyvaluepair/ckeyvaluepairequals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/ckeyvaluepair/ckeyvaluepairhashcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistcapacity2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistcount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylisttrimexcess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylisttrygetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylisttrysetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistaddrange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistinsertrange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistcopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistbinarysearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistindexof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistlastindexof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistremoveat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistremoverange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistreverse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/carraylist/carraylistsort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmapadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmapcount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmapcomparer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmapcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmapcontainskey2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmapcontainsvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmapcopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmapclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmapremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmaptrygetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashmap/chashmaptrysetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetcount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetcomparer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsettrimexcess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetcopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetexceptwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetintersectwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetsymmetricexceptwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetunionwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetispropersubsetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetispropersupersetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetissubsetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetissupersetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetoverlaps2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/chashset/chashsetsetequals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistaddafter2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistaddbefore2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistaddfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistaddlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistcount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlisthead2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistcopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistremovefirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistremovelast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistfind2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/clinkedlist/clinkedlistfindlast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueueadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueueenqueue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueuecount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueuecontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueuetrimexcess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueuecopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueueclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueueremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueuedequeue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cqueue/cqueuepeek2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreeadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreecount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreeroot2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreecontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreecomparer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreetrygetmin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreetrygetmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreecopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreeclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreeremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreeremovemin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreeremovemax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreefind2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreefindmin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/credblacktree/credblacktreefindmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmapadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmapcount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmapcomparer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmapcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmapcontainskey2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmapcontainsvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmapcopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmapclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmapremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmaptrygetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedmap/csortedmaptrysetvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetcount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetcomparer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsettrygetmin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsettrygetmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetcopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetexceptwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetintersectwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetsymmetricexceptwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetunionwith2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetispropersubsetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetispropersupersetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetissubsetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetissupersetof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetoverlaps2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetsetequals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetgetviewbetween2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/csortedset/csortedsetgetreverse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstackadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstackcount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstackcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstacktrimexcess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstackcopyto2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstackclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstackremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstackpush2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstackpeek2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/cstack/cstackpop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/arraybinarysearch2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/arrayindexof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/arraylastindexof2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/arrayreverse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/compare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/equals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/generic/gethashcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilehandle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilefilename2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfileflags2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilesetunicode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilesetcommon2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfileopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfileclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfiledelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfileisexist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilecopy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilemove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilesize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfiletell2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfileseek2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfileflush2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfileisending2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfileislineending2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilefoldercreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilefolderdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilefolderclean2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilefilefindfirst2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilefilefindnext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfile/cfilefilefindclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwritechar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwriteshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwriteinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwritelong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwritefloat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwritedouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwritestring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwritechararray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwriteshortarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwriteintegerarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwritelongarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwritefloatarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwritedoublearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinwriteobject2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadchar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadfloat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreaddouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadchararray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadshortarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadintegerarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadlongarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadfloatarray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreaddoublearray2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfilebin/cfilebinreadobject2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfiletxt2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfiletxt/cfiletxtopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfiletxt/cfiletxtwritestring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/fileoperations/cfiletxt/cfiletxtreadstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringstr2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringlen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringcopy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringfill2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringassign2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringappend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringcompare2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringcomparenocase2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringmid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringtrim2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringtrimleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringtrimright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringclear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringtoupper2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringtolower2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringreverse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringfind2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringfindrev2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringremove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/stringoperations/cstring/cstringreplace2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectchartid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectwindow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectnumpoints2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectattach2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectsetpoint2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectdetach2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectshiftobject2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectshiftpoint2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjecttime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectprice2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectstyle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectwidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectselected2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectselectable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectdescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjecttooltip2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjecttimeframes2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectz_order2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectcreatetime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectlevelscount2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectlevelcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectlevelstyle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectlevelwidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectlevelvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectleveldescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectgetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectsetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectgetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectsetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectgetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectsetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjectload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/cchartobject/cchartobjecttype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjectvline2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjectvline/cchartobjectvlinecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjectvline/cchartobjectvlinetype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecthline2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecthline/cchartobjecthlinecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecthline/cchartobjecthlinetype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrend/cchartobjecttrendcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrend/cchartobjecttrendrayleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrend/cchartobjecttrendrayright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrend/cchartobjecttrendsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrend/cchartobjecttrendload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrend/cchartobjecttrendtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrendbyangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrendbyangle/cchartobjecttrendbyanglecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrendbyangle/cchartobjecttrendbyangleangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjecttrendbyangle/cchartobjecttrendbyangletype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjectcycles2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjectcycles/cchartobjectcyclescreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_lines/cchartobjectcycles/cchartobjectcyclestype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectchannel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectchannel/cchartobjectchannelcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectchannel/cchartobjectchanneltype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectregression2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectregression/cchartobjectregressioncreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectregression/cchartobjectregressiontype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectstddevchannel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectstddevchannel/cchartobjectstddevchannelcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectstddevchannel/cchartobjectstddevchanneldeviations2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectstddevchannel/cchartobjectstddevchannelsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectstddevchannel/cchartobjectstddevchannelload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectstddevchannel/cchartobjectstddevchanneltype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectpitchfork2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectpitchfork/cchartobjectpitchforkcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_channels/cchartobjectpitchfork/cchartobjectpitchforktype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannline2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannline/cchartobjectgannlinecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannline/cchartobjectgannlinepipsperbar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannline/cchartobjectgannlinesave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannline/cchartobjectgannlineload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannline/cchartobjectgannlinetype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannfan2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannfan/cchartobjectgannfancreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannfan/cchartobjectgannfanpipsperbar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannfan/cchartobjectgannfandowntrend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannfan/cchartobjectgannfansave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannfan/cchartobjectgannfanload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectgannfan/cchartobjectgannfantype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectganngrid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectganngrid/cchartobjectganngridcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectganngrid/cchartobjectganngridpipsperbar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectganngrid/cchartobjectganngriddowntrend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectganngrid/cchartobjectganngridsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectganngrid/cchartobjectganngridload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_gann/cchartobjectganngrid/cchartobjectganngridtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibo2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibo/cchartobjectfibocreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibo/cchartobjectfibotype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibotimes2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibotimes/cchartobjectfibotimescreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibotimes/cchartobjectfibotimestype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibofan2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibofan/cchartobjectfibofancreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibofan/cchartobjectfibofantype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboarc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboarc/cchartobjectfiboarccreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboarc/cchartobjectfiboarcscale2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboarc/cchartobjectfiboarcellipse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboarc/cchartobjectfiboarcsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboarc/cchartobjectfiboarcload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboarc/cchartobjectfiboarctype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibochannel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibochannel/cchartobjectfibochannelcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfibochannel/cchartobjectfibochanneltype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboexpansion2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboexpansion/cchartobjectfiboexpansioncreat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_fibonacci/cchartobjectfiboexpansion/cchartobjectfiboexpansiontype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave32026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave3/cchartobjectelliottwave3create2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave3/cchartobjectelliottwave3degree2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave3/cchartobjectelliottwave3lines2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave3/cchartobjectelliottwave3save2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave3/cchartobjectelliottwave3load2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave3/cchartobjectelliottwave3type2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave52026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave5/cchartobjectelliottwave5create2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_elliott/cchartobjectelliottwave5/cchartobjectelliottwave5type2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes/cchartobjectrectangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes/cchartobjectrectangle/cchartobjectrectanglecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes/cchartobjectrectangle/cchartobjectrectangletype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes/cchartobjecttriangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes/cchartobjecttriangle/cchartobjecttrianglecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes/cchartobjecttriangle/cchartobjecttriangletype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes/cchartobjectellipse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes/cchartobjectellipse/cchartobjectellipsecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_shapes/cchartobjectellipse/cchartobjectellipsetype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/cchartobjectarrow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/cchartobjectarrow/cchartobjectarrowcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/cchartobjectarrow/cchartobjectarrowarrowcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/cchartobjectarrow/cchartobjectarrowanchor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/cchartobjectarrow/cchartobjectarrowsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/cchartobjectarrow/cchartobjectarrowload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/cchartobjectarrow/cchartobjectarrowtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/arrowclassesfixedcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/arrowclassesfixedcode/chartobjectarrowfixedcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/arrowclassesfixedcode/chartobjectarrowfixedarrowcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_arrows/arrowclassesfixedcode/chartobjectarrowfixedtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjecttext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjecttext/cchartobjecttextcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjecttext/cchartobjecttextangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjecttext/cchartobjecttextfont2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjecttext/cchartobjecttextfontsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjecttext/cchartobjecttextanchor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjecttext/cchartobjecttextsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjecttext/cchartobjecttextload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjecttext/cchartobjecttexttype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabelcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabelx_distance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabely_distance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabelx_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabely_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabelcorner2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabeltime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabelprice2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabelsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabelload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectlabel/cchartobjectlabeltype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjecteditcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjectedittextalign2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjecteditx_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjectedity_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjecteditbackcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjecteditbordercolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/readonly2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjecteditangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjecteditsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjecteditload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectedit/cchartobjectedittype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbutton/cchartobjectbuttonstate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbutton/cchartobjectbuttonsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbutton/cchartobjectbuttonload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbutton/cchartobjectbuttontype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartx_distance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubcharty_distance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartcorner2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartx_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubcharty_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartsymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartscale2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartdatescale2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartpricescale2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubcharttime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartprice2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubchartload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectsubchart/cchartobjectsubcharttype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbitmap2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbitmap/cchartobjectbitmapcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbitmap/cchartobjectbitmapbmpfile2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbitmap/cchartobjectbitmapx_offset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbitmap/cchartobjectbitmapy_offset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbitmap/cchartobjectbitmapsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbitmap/cchartobjectbitmapload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbitmap/cchartobjectbitmaptype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelx_distance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabely_distance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelx_offset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabely_offset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelcorner2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelx_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabely_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelbmpfileon2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelbmpfileoff2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelstate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabeltime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelprice2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabelload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectbmplabel/cchartobjectbmplabeltype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel/cchartobjectrectlabelcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel/cchartobjectrectlabelx_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel/cchartobjectrectlabely_size2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel/cchartobjectrectlabelbackcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel/cchartobjectrectlabelangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel/cchartobjectrectlabelbordertype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel/cchartobjectrectlabelsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel/cchartobjectrectlabelload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/chart_object_classes/obj_controls/cchartobjectrectlabel/cchartobjectrectlabeltype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasattach2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasarc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspie2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfillpolygon2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfillellipse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasgetdefaultcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaschartobjectname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvascircle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvascircleaa2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvascirclewu2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvascreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvascreatebitmap2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvascreatebitmaplabel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasdestroy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasellipse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasellipseaa2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasellipsewu2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaserase2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfill2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfillcircle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfillrectangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfilltriangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontangleget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontangleset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontflagsget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontflagsset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontnameget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontnameset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontsizeget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasfontsizeset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasheight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasline2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaslineaa2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaslinewu2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaslinehorizontal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaslinevertical2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaslinestyleset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaslinethick2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaslinethickvertical2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaslinethickhorizontal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasloadfromfile2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspixelget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspixelset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspixelsetaa2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolygon2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolygonaa2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolygonwu2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolygonthick2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolygonsmooth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolyline2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolylinesmooth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolylinethick2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolylinewu2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaspolylineaa2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasrectangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasresourcename2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvastextheight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvastextout2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvastextsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvastextwidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvastransparentlevelset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvastriangle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvastriangleaa2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvastrianglewu2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvasupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/ccanvas/ccanvaswidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvascolorbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvascolorborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvascolortext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvascolorgrid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasmaxdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasmaxdescrlen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowflags2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasisshowlegend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasisshowscaleleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasisshowscaleright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasisshowscaletop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasisshowscalebottom2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasisshowgrid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasisshowdescriptors2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasisshowpercent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasvscalemin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasvscalemax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasnumgrid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdataoffset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdatatotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawdescriptors2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvascreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasallowedshowflags2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowlegend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowscaleleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowscaleright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowscaletop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowscalebottom2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowgrid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowdescriptors2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasshowpercent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvaslegendalignment2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasaccumulative2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasvscaleparams2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdescriptorupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvascolorupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasvaluescheck2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasredraw2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawlegend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawlegendvertical2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawlegendhorizontal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvascalcscales2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawscales2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawscaleleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawscaleright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawscaletop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawscalebottom2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawgrid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cchartcanvas/cchartcanvasdrawchart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartgradient2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartbargap2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartbarminsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartbarborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartseriesadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartseriesinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartseriesupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartseriesdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartvalueupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartdrawdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartdrawbar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/chistogramchart/chistogramchartgradientbrush2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartfilled2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartseriesadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartseriesinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartseriesupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartseriesdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartvalueupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartdrawchart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartdrawdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/clinechart/clinechartcalcarea2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart/cpiechartcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart/cpiechartseriesset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart/cpiechartvalueadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart/cpiechartvalueinsert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart/cpiechartvalueupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart/cpiechartvaluedelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart/cpiechartdrawchart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart/cpiechartdrawpie2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/canvasgraphics/cpiechart/cpiechartlabelmake2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dambientcolorget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dambientcolorset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dattach2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3ddestroy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3ddxcontext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3ddxdispatcher2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dinputscene2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dlightcolorget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dlightcolorset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dlightdirectionget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dlightdirectionset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dobjectadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dprojectionmatrixget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dprojectionmatrixset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3drender2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3drenderbegin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3drenderend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dviewmatrixget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dviewmatrixset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dviewpositionset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dviewrotationset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dviewtargetset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/3dgraphics/ccanvas3d/ccanvas3dviewupdirectionset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartchartid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartmode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartforeground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshiftsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartautoscroll2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartscale2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartscalefix2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartscalefix_112026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartfixedmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartfixedmin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartpointsperbar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartscaleppb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowohlc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowlinebid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowlineask2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowlastline2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowperiodsep2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowgrid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowvolumes2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowobjectdescr2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowdatescale2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartshowpricescale2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorforeground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorgrid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorbarup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorbardown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorcandlebull2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorcandlebear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorchartline2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorvolumes2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorlinebid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorlineask2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorlinelast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartcolorstoplevels2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartvisiblebars2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartwindowstotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartwindowisvisible2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartwindowhandle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartfirstvisiblebar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartwidthinbars2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartwidthinpixels2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartheightinpixels2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartpricemin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartpricemax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartattach2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartfirstchart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartnextchart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartdetach2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartbringtotop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/ccharteventobjectcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/ccharteventobjectdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartindicatoradd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartindicatordelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartindicatorstotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartindicatorname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartnavigate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartsymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartredraw2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartgetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartsetinteger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartgetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartsetdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartgetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartsetstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartsetsymbolperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartapplytemplate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartscreenshot2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartwindowondropped2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartpriceondropped2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/ccharttimeondropped2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartxondropped2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartyondropped2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartsave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/cchart/cchartype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/graphplot2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisautoscale2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxismin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxismax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisstep2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxiscolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisvaluessize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisvalueswidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisvaluesformat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisvaluesdatetimemode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisvaluesfunctionformat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisvaluesfunctionformatcbdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisnamesize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxiszerolever2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisdefaultstep2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxismaxlabels2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxismingrace2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxismaxgrace2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/caxis/caxisselectaxisscale2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccolorgenerator2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccolorgenerator/ccolorgeneratornext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccolorgenerator/ccolorgeneratorreset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvetype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvename2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvecolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvexmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvexmin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurveymax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurveymin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvesize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvepointssize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvepointsfill2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvepointscolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvegetx2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvegety2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvelinesstyle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvelinesissmooth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvelinessmoothtension2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvelinessmoothstep2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvelinesendstyle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvelineswidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvehistogramwidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvecustomplotcbdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvecustomplotfunction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvepointstype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvestepsdimension2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvetrendlinecoefficients2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvetrendlinecolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvetrendlinevisible2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurveupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/ccurve/ccurvevisible2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicdestroy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicchartobjectname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicresourcename2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicxaxis2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicyaxis2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicgapsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicbackgroundcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicbackgroundmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicbackgroundmainsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicbackgroundmaincolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicbackgroundsub2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicbackgroundsubsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicbackgroundsubcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicgridlinecolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicgridbackgroundcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicgridvcircleradius2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicgridcirclecolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicgridhascircle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicgridaxislinecolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphichistorynamewidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphichistorynamesize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphichistorysymbolsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphictextadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiclineadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccurveadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccurveplot2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccurveplotall2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccurvegetbyindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccurvegetbyname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccurveremovebyindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccurveremovebyname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccurvestotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicmarkstoaxisadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicmajormarksize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicfontset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicfontget2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicattach2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphiccalculatemaxminvalues2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicheight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicindentdown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicindentleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicindentright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicindentup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicredraw2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicresetparameters2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicscalex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicscaley2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicsetdefaultparameters2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/graphics/cgraphic/cgraphicwidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cspreadbuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cspreadbuffer/cspreadbuffersize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cspreadbuffer/cspreadbuffersetsymbolperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cspreadbuffer/cspreadbufferat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cspreadbuffer/cspreadbufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cspreadbuffer/cspreadbufferrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctimebuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctimebuffer/ctimebuffersize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctimebuffer/ctimebuffersetsymbolperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctimebuffer/ctimebufferat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctimebuffer/ctimebufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctimebuffer/ctimebufferrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctickvolumebuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctickvolumebuffer/ctickvolumebuffersize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctickvolumebuffer/ctickvolumebuffersetsymbolperi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctickvolumebuffer/ctickvolumebufferat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctickvolumebuffer/ctickvolumebufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/ctickvolumebuffer/ctickvolumebufferrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/crealvolumebuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/crealvolumebuffer/crealvolumebuffersize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/crealvolumebuffer/crealvolumebuffersetsymbolperi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/crealvolumebuffer/crealvolumebufferat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/crealvolumebuffer/crealvolumebufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/crealvolumebuffer/crealvolumebufferrefreshcurren2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cdoublebuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cdoublebuffer/cdoublebuffersize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cdoublebuffer/cdoublebuffersetsymbolperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cdoublebuffer/cdoublebufferat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cdoublebuffer/cdoublebufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cdoublebuffer/cdoublebufferrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/copenbuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/copenbuffer/copenbufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/copenbuffer/copenbufferrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/chighbuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/chighbuffer/chighbufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/chighbuffer/chighbufferrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/clowbuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/clowbuffer/clowbufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/clowbuffer/clowbufferrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cclosebuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cclosebuffer/cclosebufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cclosebuffer/cclosebufferrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicatorbuffer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicatorbuffer/cindicatorbufferoffset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicatorbuffer/cindicatorbuffername2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicatorbuffer/cindicatorbufferat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicatorbuffer/cindicatorbufferrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicatorbuffer/cindicatorbufferrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriesname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriesbufferstotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriestimeframe2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriessymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriesperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriesrefreshcurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriesbuffersize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriesbufferresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriesrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cseries/cseriesperioddescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cpriceseries2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cpriceseries/cpriceseriesbufferresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cpriceseries/cpriceseriesgetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cpriceseries/cpriceseriesrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cpriceseries/cpriceseriesminindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cpriceseries/cpriceseriesminvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cpriceseries/cpriceseriesmaxindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cpriceseries/cpriceseriesmaxvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorhandle2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorstatus2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorfullrelease2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorbufferresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorbarscalculated2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorgetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorminimum2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorminvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatormaximum2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatormaxvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatormethoddescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorpricedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatorvolumedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatoraddtochart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicator/cindicatordeletefromchart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicators22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicators2/cindicatorscreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/cindicators/cindicators2/cindicatorsrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cispread2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cispread/cispreadcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cispread/cispreadbufferresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cispread/cispreadgetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cispread/cispreadrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citime/citimecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citime/citimebufferresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citime/citimegetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citime/citimerefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citickvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citickvolume/citickvolumecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citickvolume/citickvolumebufferresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citickvolume/citickvolumegetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/citickvolume/citickvolumerefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cirealvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cirealvolume/cirealvolumecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cirealvolume/cirealvolumebufferresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cirealvolume/cirealvolumegetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cirealvolume/cirealvolumerefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/ciopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/ciopen/ciopencreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/ciopen/ciopengetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cihigh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cihigh/cihighcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cihigh/cihighgetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cilow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cilow/cilowcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/cilow/cilowgetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/ciclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/ciclose/ciclosecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/timeseries/ciclose/ciclosegetdata2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadx2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadx/ciadxmaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadx/ciadxcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadx/ciadxmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadx/ciadxplus2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadx/ciadxminus2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadx/ciadxtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadxwilder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadxwilder/ciadxwildermaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadxwilder/ciadxwildercreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadxwilder/ciadxwildermain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadxwilder/ciadxwilderplus2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadxwilder/ciadxwilderminus2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciadxwilder/ciadxwildertype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands/cibandsmaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands/cibandsmashift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands/cibandsdeviation2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands/cibandsapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands/cibandscreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands/cibandsbase2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands/cibandsupper2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands/cibandslower2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cibands/cibandstype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes/cienvelopesmaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes/cienvelopesmashift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes/cienvelopesmamethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes/cienvelopesdeviation2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes/cienvelopesapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes/cienvelopescreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes/cienvelopesupper2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes/cienvelopeslower2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cienvelopes/cienvelopestype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokutenkansenperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokukijunsenperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokusenkouspanbperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokucreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokutenkansen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokukijunsen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokusenkouspana2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokusenkouspanb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokuchinkouspan2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciichimoku/ciichimokutype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cima2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cima/cimamaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cima/cimamashift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cima/cimamamethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cima/cimaapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cima/cimacreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cima/cimamain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cima/cimatype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cisar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cisar/cisarsarstep2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cisar/cisarmaximum2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cisar/cisarcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cisar/cisarmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cisar/cisartype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cistddev2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cistddev/cistddevmaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cistddev/cistddevmashift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cistddev/cistddevmamethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cistddev/cistddevapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cistddev/cistddevcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cistddev/cistddevmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cistddev/cistddevtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cidema2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cidema/cidemamaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cidema/cidemaindshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cidema/cidemaapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cidema/cidemacreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cidema/cidemamain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cidema/cidematype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/citema2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/citema/citemamaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/citema/citemaindshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/citema/citemaapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/citema/citemacreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/citema/citemamain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/citema/citematype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciframa2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciframa/ciframamaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciframa/ciframaindshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciframa/ciframaapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciframa/ciframacreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciframa/ciframamain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciframa/ciframatype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciama2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciama/ciamamaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciama/ciamafastemaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciama/ciamaslowemaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciama/ciamaindshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciama/ciamaapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciama/ciamacreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciama/ciamamain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/ciama/ciamatype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cividya2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cividya/cividyacmoperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cividya/cividyaemaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cividya/cividyaindshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cividya/cividyaapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cividya/cividyacreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cividya/cividyamain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/trendindicators/cividya/cividyatype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciatr2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciatr/ciatrmaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciatr/ciatrcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciatr/ciatrmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciatr/ciatrtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibearspower2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibearspower/cibearspowermaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibearspower/cibearspowercreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibearspower/cibearspowermain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibearspower/cibearspowertype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibullspower2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibullspower/cibullspowermaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibullspower/cibullspowercreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibullspower/cibullspowermain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cibullspower/cibullspowertype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cicci2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cicci/ciccimaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cicci/cicciapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cicci/ciccicreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cicci/ciccimain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cicci/ciccitype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cichaikin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cichaikin/cichaikinfastmaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cichaikin/cichaikinslowmaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cichaikin/cichaikinmamethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cichaikin/cichaikinapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cichaikin/cichaikincreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cichaikin/cichaikinmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cichaikin/cichaikintype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cidemarker2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cidemarker/cidemarkermaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cidemarker/cidemarkercreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cidemarker/cidemarkermain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cidemarker/cidemarkertype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciforce2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciforce/ciforcemaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciforce/ciforcemamethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciforce/ciforceapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciforce/ciforcecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciforce/ciforcemain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciforce/ciforcetype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimacd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimacd/cimacdfastemaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimacd/cimacdslowemaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimacd/cimacdsignalperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimacd/cimacdapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimacd/cimacdcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimacd/cimacdmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimacd/cimacdsignal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimacd/cimacdtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimomentum2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimomentum/cimomentummaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimomentum/cimomentumapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimomentum/cimomentumcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimomentum/cimomentummain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cimomentum/cimomentumtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciosma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciosma/ciosmafastemaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciosma/ciosmaslowemaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciosma/ciosmasignalperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciosma/ciosmaapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciosma/ciosmacreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciosma/ciosmamain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciosma/ciosmatype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirsi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirsi/cirsimaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirsi/cirsiapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirsi/cirsicreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirsi/cirsimain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirsi/cirsitype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirvi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirvi/cirvimaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirvi/cirvicreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirvi/cirvimain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirvi/cirvisignal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cirvi/cirvitype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic/cistochastickperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic/cistochasticdperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic/cistochasticslowing2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic/cistochasticmamethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic/cistochasticpricefield2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic/cistochasticcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic/cistochasticmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic/cistochasticsignal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/cistochastic/cistochastictype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/citrix2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/citrix/citrixmaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/citrix/citrixapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/citrix/citrixcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/citrix/citrixmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/citrix/citrixtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciwpr2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciwpr/ciwprcalcperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciwpr/ciwprcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciwpr/ciwprmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/oscillatorindicators/ciwpr/ciwprtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciad2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciad/ciadapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciad/ciadcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciad/ciadmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciad/ciadtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/cimfi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/cimfi/cimfimaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/cimfi/cimfiapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/cimfi/cimficreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/cimfi/cimfimain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/cimfi/cimfitype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciobv2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciobv/ciobvapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciobv/ciobvcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciobv/ciobvmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/ciobv/ciobvtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/civolumes2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/civolumes/civolumesapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/civolumes/civolumescreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/civolumes/civolumesmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/volumeindicators/civolumes/civolumestype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/ciac2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/ciac/ciaccreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/ciac/ciacmain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/ciac/ciactype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorjawperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorjawshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorteethperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorteethshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorlipsperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorlipsshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatormamethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorjaw2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorteeth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatorlips2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cialligator/cialligatortype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/ciao2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/ciao/ciaocreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/ciao/ciaomain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/ciao/ciaotype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cifractals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cifractals/cifractalscreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cifractals/cifractalsupper2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cifractals/cifractalslower2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cifractals/cifractalstype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorjawperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorjawshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorteethperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorteethshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorlipsperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorlipsshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatormamethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorupper2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatorlower2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cigator/cigatortype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cibwmfi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cibwmfi/cibwmfiapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cibwmfi/cibwmficreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cibwmfi/cibwmfimain2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/bwindicators/cibwmfi/cibwmfitype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/customindicator2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/customindicator/cicustomnumbuffers2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/customindicator/cicustomnumparams2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/customindicator/cicustomparamtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/customindicator/cicustomparamlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/customindicator/cicustomparamdouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/customindicator/cicustomparamstring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/technicalindicators/customindicator/cicustomtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfologin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfotrademode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfotrademodedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfoleverage2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfostopoutmode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfostopoutmodedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfomarginmode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfomarginmodedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfotradeallowed2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfotradeexpert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfolimitorders2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfobalance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfocredit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfoprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfoequity2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfomargin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfofreemargin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfomarginlevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfomargincall2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfomarginstopout2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfoname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfoserver2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfocurrency2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfocompany2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfointeger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfodouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfostring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfoorderprofitcheck2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfomargincheck2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfofreemargincheck2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/caccountinfo/caccountinfomaxlotcheck2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinforefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinforefreshrates2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoissynchronized2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfovolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfovolumehigh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfovolumelow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfospread2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfospreadfloat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoticksbookdepth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfostopslevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfofreezelevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfobid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfobidhigh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfobidlow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoask2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoaskhigh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoasklow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfolast2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfolasthigh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfolastlow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotradecalcmode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotradecalcmodedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotrademode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotrademodedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotradeexecution2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotradeexecutiondescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoswapmode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoswapmodedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoswaprollover3days2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoswaprollover3daysdescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfomargininitial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfomarginmaintenance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfomarginlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfomarginshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfomarginlimit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfomarginstop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfomarginstoplimit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotradetimeflags2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotradefillflags2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfodigits2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfopoint2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotickvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotickvalueprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfotickvalueloss2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoticksize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfocontractsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfolotsmin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfolotsmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfolotsstep2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfolotslimit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoswaplong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoswapshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfocurrencybase2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfocurrencyprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfocurrencymargin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfobank2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfodescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfopath2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessiondeals2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionbuyorders2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionsellorders2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionturnover2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessioninterest2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionbuyordersvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionsellordersvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionaw2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionpricesettlement2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionpricelimitmin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfosessionpricelimitmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoinfointeger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoinfodouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfoinfostring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/csymbolinfo/csymbolinfonormalizeprice2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfoticket2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotimesetup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotimesetupmsc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfoordertype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotypedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfostate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfostatedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotimeexpiration2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotimedone2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotimedonemsc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotypefilling2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotypefillingdescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotypetime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotypetimedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfomagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfopositionid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfovolumeinitial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfovolumecurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfopriceopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfostoploss2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfotakeprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfopricecurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfopricestoplimit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfosymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfocomment2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfoinfointeger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfoinfodouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfoinfostring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfostorestate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfocheckstate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfoselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/corderinfo/corderinfoselectbyindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotimesetup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotimesetupmsc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfoordertype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotypedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfostate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfostatedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotimeexpiration2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotimedone2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotimedonemsc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotypefilling2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotypefillingdescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotypetime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotypetimedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfomagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfopositionid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfovolumeinitial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfovolumecurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfopriceopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfostoploss2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfotakeprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfopricecurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfopricestoplimi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfosymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfocomment2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfoinfointeger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfoinfodouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfoinfostring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfoticket2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/chistoryorderinfo/chistoryorderinfoselectbyindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfotime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfotimemsc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfotimeupdate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfotimeupdatemsc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfopositiontype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfotypedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfomagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoidentifier2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfovolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfopriceopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfostoploss2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfotakeprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfopricecurrent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfocommission2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoswap2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfosymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfocomment2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoinfointeger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoinfodouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoinfostring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoselectbyindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoselectbymagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfoselectbyticket2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfostorestate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cpositioninfo/cpositioninfocheckstate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoorder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfotime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfotimemsc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfodealtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfotypedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoentry2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoentrydescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfomagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfopositionid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfovolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoprice2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfocommision2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoswap2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfosymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfocomment2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoinfointeger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoinfodouble2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoinfostring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoticket2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cdealinfo/cdealinfoselectbyindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradeloglevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradesetexpertmagicnumber2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradesetdeviationinpoints2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradesettypefilling2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradesettypefillingbysymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradesetasyncmode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradesetmargingmode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradeorderopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradeordermodify2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradeorderdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradepositionopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradepositionmodify2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradepositionclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradepositionclosepartial2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradepositioncloseby2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradebuy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradesell2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradebuylimit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradebuystop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradeselllimit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradesellstop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequest2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestaction2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestactiondescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestmagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestorder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestsymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestprice2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequeststoplimit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestsl2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequesttp2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestdeviation2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequesttype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequesttypedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequesttypefilling2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequesttypefillingdescri2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequesttypetime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequesttypetimedescripti2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestexpiration2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestcomment2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestrequestposition2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderequestrequestpositionby2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesult2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesultretcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesultretcodedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesultdeal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesultorder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesultvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesultprice2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesultbid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesultask2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctraderesultcomment2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresult2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresultretcode2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresultretcodedescription2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresultbalance2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresultequity2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresultprofit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresultmargin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresultmarginfree2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresultmarginlevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradecheckresultcomment2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradeprintrequest2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradeprintresult2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradeformatrequest2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/ctrade/ctradeformatrequestresult2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfobuild2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoisconnected2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoisdllsallowed2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoistradeallowed2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoisemailenabled2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoisftpenabled2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfomaxbars2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfocodepage2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfocpucores2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfomemoryphysical2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfomemorytotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfomemoryavailable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfomemoryused2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoisx642026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoopenclsupport2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfodiskspace2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfolanguage2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfocompany2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfopath2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfodatapath2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfocommondatapath2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoinfointeger2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/tradeclasses/cterminalinfo/cterminalinfoinfostring2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinitphase2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasetrendtype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseusedseries2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseeverytick2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasehigh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaselow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasespread2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasetime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasetickvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaserealvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasesymbol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasemagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasevalidationsettings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasesetpriceseries2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasesetotherseries2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinitindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinitopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinithigh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinitlow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinitclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinitspread2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinittime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinittickvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbaseinitrealvolume2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasepricelevelunit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasestartindex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertbase/cexpertbasecomparemagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertinit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertmagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertinitsignal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertinittrailing2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertinitmoney2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertinittrade2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeinit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertontickprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertontradeprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertontimerprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertoncharteventprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertonbookeventprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertmaxorders2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertsignal22026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertvalidationsettings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertinitindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertontick2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertontrade2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertontimer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertonchartevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertonbookevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertinitparameters2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeinittrade2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeinitsignal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeinittrailing2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeinitmoney2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeinitindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertrefresh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertprocessing2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertselectposition2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckreverse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckreverselong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckreverseshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertreverselong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertreverseshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckcloselong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckcloseshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcloseall2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcloselong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcloseshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertchecktrailingstop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertchecktrailingstoplong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertchecktrailingstopshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttrailingstoplong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttrailingstopshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertchecktrailingorderlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertchecktrailingordershort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttrailingorderlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttrailingordershort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckdeleteorderlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertcheckdeleteordershort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeleteorders2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeleteorder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeleteorderlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertdeleteordershort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertlotopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertlotopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertlotreverse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertpreparehistorydate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperthistorypoint2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertchecktradestate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertwaitevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexpertnowaitevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventpositionstoptake2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventordertriggered2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventpositionopened2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventpositionvolumechanged2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventpositionmodified2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventpositionclosed2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventorderplaced2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventordermodified2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventorderdeleted2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttradeeventnotidentified2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttimeframeadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpert/cexperttimeframesflags2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalbaseprice2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalusedseries2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalweight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalpatternsusage2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalgeneral2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalignore2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalinvert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalthresholdopen2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalthresholdclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalpricelevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalstoplevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignaltakelevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalexpiration2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalmagic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalvalidationsettings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalinitindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignaladdfilter2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalcheckopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalcheckopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalopenlongparams2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalopenshortparams2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalcheckcloselong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalcheckcloseshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalcloselongparams2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalcloseshortparams2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalcheckreverselong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalcheckreverseshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalchecktrailingorderlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalchecktrailingordershort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignallongcondition2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignalshortcondition2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertsignal/cexpertsignaldirection2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexperttrailing2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexperttrailing/cexperttrailingchecktrailingstoplong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexperttrailing/cexperttrailingchecktrailingstopshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertmoney2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertmoney/cexpertmoneypercent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertmoney/cexpertmoneyvalidationsettings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertmoney/cexpertmoneycheckopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertmoney/cexpertmoneycheckopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertmoney/cexpertmoneycheckreverse2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/expertbaseclasses/cexpertmoney/cexpertmoneycheckclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_ac2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_ama2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_ao2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_bears2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_bulls2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_cci2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_demarker2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_dema2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_envelopes2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_frama2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_time_filter2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_macd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_ma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_sar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_rsi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_rvi2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_stochastic2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_trix2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_tema2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/csignal/signal_wpr2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingfixedpips2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingfixedpips/ctrailingfixedpipsstoplevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingfixedpips/ctrailingfixedpipsprofitlevel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingfixedpips/ctrailingfixedpipsvalidationsettings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingfixedpips/ctrailingfixedpipschecktrailingstoplong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingfixedpips/ctrailingfixedpipschecktrailingstopshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingma2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingma/ctrailingmaperiod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingma/ctrailingmashift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingma/ctrailingmamethod2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingma/ctrailingmaapplied2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingma/ctrailingmainitindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingma/ctrailingmavalidationsettings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingma/ctrailingmachecktrailingstoplong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingma/ctrailingmachecktrailingstopshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingnone2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingnone/ctrailingnonechecktrailingstoplong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingnone/ctrailingnonechecktrailingstopshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingpsar2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingpsar/trailingparabolicsarstep2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingpsar/trailingparabolicsarmaximum2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingpsar/trailingparabolicsarinitindicators2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingpsar/trailingparabolicsarchecktrailingstoplong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/sampletrailingclasses/ctrailingpsar/trailingparabolicsarchecktrailingstopshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedlot2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedlot/cmoneyfixedlotlots2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedlot/cmoneyfixedlotvalidationsettings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedlot/cmoneyfixedlotcheckopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedlot/cmoneyfixedlotcheckopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedmargin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedmargin/moneyfixedmargincheckopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedmargin/moneyfixedmargincheckopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedrisk2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedrisk/cmoneyfixedriskcheckopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneyfixedrisk/cmoneyfixedriskcheckopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneynone2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneynone/cmoneynonevalidationsettings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneynone/cmoneynonecheckopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneynone/cmoneynonecheckopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneysizeoptimized2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneysizeoptimized/cmoneysizeoptimizeddecreasefactor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneysizeoptimized/cmoneysizeoptimizedvalidationsettings2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneysizeoptimized/cmoneysizeoptimizedcheckopenlong2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/expertclasses/samplemmclasses/cmoneysizeoptimized/cmoneysizeoptimizedcheckopenshort2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crecttop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectbottom2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectwidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectheight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectsetbound2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectmove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/crect/crectformat2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimemonthname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimeshortmonthname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimedayname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimeshortdayname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimedaysinmonth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimedatetime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimedate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimetime2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimesec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimemin2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimehour2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimeday2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimemon2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimeyear2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimesecdec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimesecinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimemindec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimemininc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimehourdec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimehourinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimedaydec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimedayinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimemondec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimemoninc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimeyeardec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdatetime/cdatetimeyearinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwnddestroy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonmouseevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndcontrolstotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndcontrol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndcontrolfind2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndrect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndtop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndbottom2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndwidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndheight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndmove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndshift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndcontains2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndalignment2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndalign2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndisenabled2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndenable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwnddisable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndisvisible2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndvisible2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndisactive2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndactivate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwnddeactivate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndstateflags2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndstateflagsset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndstateflagsreset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndpropflags2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndpropflagsset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndpropflagsreset2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndmousex2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndmousey2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndmouseflags2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndmousefocuskill2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndoncreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndondestroy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonmove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonenable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndondisable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonactivate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndondeactivate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonclick2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonchange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonmousedown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndonmouseup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndondragstart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndondragprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwndondragend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwnddragobjectcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwnd/cwnddragobjectdestroy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjtext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjcolorbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjcolorborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjfont2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjfontsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjzorder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonobjectcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonobjectchange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonobjectdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonobjectdrag2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonsettext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonsetcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonsetcolorbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonsetfont2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonsetfontsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonsetzorder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjondestroy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndobj/cwndobjonchange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainerdestroy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontaineronevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontaineronmouseevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainercontrolstotal2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainercontrol2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainercontrolfind2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontaineradd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainerdelete2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainermove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainershift2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainerid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainerenable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainerdisable2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainershow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainerhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainermousefocuskill2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainersave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainerload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontaineronresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontaineronactivate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndcontainer/cwndcontainerondeactivate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel/clabelcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel/clabelonsettext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel/clabelonsetcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel/clabelonsetfont2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel/clabelonsetfontsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel/clabeloncreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel/clabelonshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel/clabelonhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clabel/clabelonmove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttoncreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttonborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttonbmpnames2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttonbmpoffname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttonbmponname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttonbmppassivename2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttonbmpactivename2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttonpressed2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttonlocking2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttononsetzorder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttononcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttononshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttononhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttononmove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttononchange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttononactivate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttonondeactivate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttononmousedown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbmpbutton/cbmpbuttononmouseup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttoncreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttonpressed2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttonlocking2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononsettext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononsetcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononsetcolorbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononsetcolorborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononsetfont2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononsetfontsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononmove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononmousedown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cbutton/cbuttononmouseup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditreadonly2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/cedittextalign2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonobjectendedit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonsettext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonsetcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonsetcolorbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonsetcolorborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonsetfont2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonsetfontsize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonsetzorder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditoncreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonmove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonchange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cedit/ceditonclick2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelbordertype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelonsettext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelonsetcolorbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelonsetcolorborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpaneloncreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelonshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelonhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelonmove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelonresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpanel/cpanelonchange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpicture2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpicture/cpicturecreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpicture/cpictureborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpicture/cpicturebmpname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpicture/cpictureoncreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpicture/cpictureonshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpicture/cpictureonhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpicture/cpictureonmove2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cpicture/cpictureonchange2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollminpos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollmaxpos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollcurrpos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollcreateback2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollcreateinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollcreatedec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollcreatethumb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollonclickinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollonclickdec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollonshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollonhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollonchangepos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollonthumbdragstart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollonthumbdragprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollonthumbdragend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscroll/cscrollcalcpos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv/cscrollvcreateinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv/cscrollvcreatedec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv/cscrollvcreatethumb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv/cscrollvonresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv/cscrollvonchangepos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv/cscrollvonthumbdragstart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv/cscrollvonthumbdragprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv/cscrollvonthumbdragend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollv/cscrollvcalcpos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh/cscrollhcreateinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh/cscrollhcreatedec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh/cscrollhcreatethumb2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh/cscrollhonresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh/cscrollhonchangepos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh/cscrollhonthumbdragstart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh/cscrollhonthumbdragprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh/cscrollhonthumbdragend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cscrollh/cscrollhcalcpos2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientcolorbackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientcolorborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientbordertype2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientvscrolled2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclienthscrolled2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientcreateback2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientcreatescrollv2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientcreatescrollh2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonvscrollshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonvscrollhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonhscrollshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonhscrollhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonscrolllinedown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonscrolllineup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonscrolllineleft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientonscrolllineright2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cwndclient/cwndclientrebound2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewtotalview2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewadditem2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewselectbytext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewselectbyvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewcreaterow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewonresize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewonvscrollshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewonvscrollhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewonscrolllinedown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewonscrolllineup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewonitemclick2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewredraw2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewrowstate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/clistview/clistviewcheckview2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxadditem2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxlistviewitems2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxselectbytext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxselectbyvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxcreateedit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxcreatebutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxcreatelist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxonclickedit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxonclickbutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxonchangelist2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxlistshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccombobox/ccomboboxlisthide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckboxcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckboxonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckboxtext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckboxcolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckboxchecked2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckboxvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckcreatebutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckcreatelabel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckonclickbutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckbox/ccheckonclicklabel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgroupcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgrouponevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgroupadditem2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgroupvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgroupcreatebutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgrouponvscrollshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgrouponvscrollhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgrouponscrolllinedown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgrouponscrolllineup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgrouponchangeitem2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgroupredraw2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/ccheckgroup/ccheckgrouprowstate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton/cradiobuttoncreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton/cradiobuttononevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton/cradiobuttontext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton/cradiobuttoncolor2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton/cradiobuttonstate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton/cradiobuttoncreatebutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton/cradiobuttoncreatelabel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton/cradiobuttononclickbutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiobutton/cradiobuttononclicklabel2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogroupcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogrouponevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogroupadditem2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogroupvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogroupcreatebutton2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogrouponvscrollshow2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogrouponvscrollhide2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogrouponscrolllinedown2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogrouponscrolllineup2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogrouponchangeitem2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogroupredraw2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogrouprowstate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cradiogroup/cradiogroupselect2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditminvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditmaxvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditvalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditcreateedit2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditcreateinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditcreatedec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditonclickinc2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditonclickdec2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cspinedit/cspineditonchangevalue2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogcaption2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogadd2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogcreatewhiteborder2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogcreatebackground2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogcreatecaption2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogcreatebuttonclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogcreateclientarea2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogonclickcaption2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogonclickbuttonclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogclientareavisible2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogclientarealeft2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogclientareatop2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogclientarearight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogclientareabottom2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogclientareawidth2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogclientareaheight2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogondialogdragstart2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogondialogdragprocess2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cdialog/cdialogondialogdragend2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogcreate2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogdestroy2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogonevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogrun2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogchartevent2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogminimized2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialoginifilesave2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialoginifileload2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialoginifilename2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialoginifileext2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogcreatecommon2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogcreateexpert2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogcreateindicator2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogcreatebuttonminmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogonclickbuttonclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogonclickbuttonminmax2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogonanotherapplicationclose2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogrebound2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogminimize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogmaximize2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogcreateinstanceid2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogprogramname2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/standardlibrary/controls/cappdialog/cappdialogsubwinoff2026-06-22T09:20:25+00:00monthly0.5 +https://www.mql5.com/en/docs/migration2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/function_indices2026-06-22T09:20:24+00:00monthly0.5 +https://www.mql5.com/en/docs/constant_indices2026-06-22T09:20:24+00:00monthly0.5 + \ No newline at end of file diff --git a/skills/mql5/SKILL.md b/skills/mql5/SKILL.md new file mode 100644 index 0000000..bb6fe41 --- /dev/null +++ b/skills/mql5/SKILL.md @@ -0,0 +1,505 @@ +--- +name: mql5 +description: > + MQL5 development skill for MetaTrader 5 Expert Advisors, Indicators, Scripts, + and Services. Focus on positions, orders, indicators, ticks, bars, risk + management, backtesting, and multi-instance MT5 operations. Includes + programming book and API reference documentation. +version: "0.1" +license: MIT +compatibility: > + Target: MetaTrader 5 platform. Language: MQL5 (C++-like syntax). + File extensions: *.mq5 (source), *.mqh (headers). + Run time: Windows native, Linux via Wine, macOS via Wine. +metadata: + project-version: "0.1.0" + focus-areas: + - positions + - orders + - indicators + - ticks + - bars + - risk-management + - backtesting +--- + +# MQL5 Development Skill + +Expert development skill for MetaTrader 5. Covers EA, Indicator, Script, and +Service creation with emphasis on trading operations, technical indicators, +multi-timeframe analysis, risk management, and backtesting workflows. + +## 1. MQL5 Fundamentals + +### Language and File Types + +- MQL5 syntax is similar to C++ but with domain-specific additions +- Source files: `*.mq5` (programs), `*.mqh` (headers) +- Compiled output: `*.ex5` (same name as source) +- Compiler: built into MetaEditor IDE + +### Program Types + +| Type | Purpose | Key Handler | Directory | +|------|---------|-------------|-----------| +| Expert Advisor | Automated trading | `OnTick()` | `MQL5/Experts/` | +| Indicator | Technical analysis | `OnCalculate()` | `MQL5/Indicators/` | +| Script | One-shot execution | `OnStart()` | `MQL5/Scripts/` | +| Service | Background task | `OnStart()` + `OnTimer()` | `MQL5/Services/` | + +### MQL5 Directory Structure + +Default locations per platform: + +| Platform | Path | +|----------|------| +| Windows 10+ | `$env:USERPROFILE\AppData\Roaming\MetaQuotes\Terminal\$INSTANT_HEX\MQL5` | +| Linux (Wine) | `~/.wine/drive_c/Program Files/MetaTrader 5/MQL5/` | +| macOS | Unknown — verify per installation | + +Key subdirectories: +``` +MQL5/ +├── Experts/ # EA source files (.mq5) +│ ├── Examples/ # Built-in example EAs +│ └── Free Robots/ # Downloaded EAs +├── Indicators/ # Indicator source files +├── Scripts/ # Script source files +├── Services/ # Service source files +├── Include/ # Header files (.mqh) +│ ├── Trade/ # Trading classes (Trade.mqh, PositionInfo.mqh, etc.) +│ ├── Indicators/ # Indicator helpers +│ ├── Expert/ # Expert base classes +│ └── Generic/ # Generic collections +├── Files/ # File I/O sandbox +├── Images/ # Image resources +├── Libraries/ # DLL/shared libraries +├── Profiles/ # Chart profiles +└── Logs/ # Log files +``` + +### Multi-Instance MT5 + +Multiple MT5 instances can run simultaneously for different accounts: + +1. Install MT5 to separate target paths (e.g. `MT5_BrokerA/`, `MT5_BrokerB/`) +2. Each instance has its own `MQL5/` directory +3. To identify which account an instance is logged into: + - `AccountInfoInteger(ACCOUNT_LOGIN)` — account number + - `AccountInfoString(ACCOUNT_NAME)` — account name + - `AccountInfoString(ACCOUNT_SERVER)` — broker server +4. Each instance runs as a separate process — use `Magic Number` to distinguish + EA trades across instances on the same symbol + +## 2. Trading Operations + +### Core Concepts + +- **Order**: instruction to buy/sell (Market or Pending) +- **Deal**: executed exchange (buy at Ask, sell at Bid) +- **Position**: current obligation (long or short) + +### CTrade Class (Standard Library) + +```mql5 +#include + +CTrade trade; + +// Setup in OnInit() +trade.SetExpertMagicNumber(EA_MAGIC); +trade.SetMarginMode(); +trade.SetTypeFillingBySymbol(Symbol()); +trade.SetDeviationInPoints(Slippage); +``` + +Key methods: + +| Method | Purpose | +|--------|---------| +| `PositionOpen(symbol, type, volume, price, sl, tp)` | Open a position | +| `PositionClose(symbol, deviation)` | Close a position | +| `PositionModify(symbol, sl, tp)` | Modify SL/TP | +| `PositionClosePartial(symbol, volume)` | Partial close | +| `Buy(volume, price, sl, tp, comment)` | Shortcut for buy | +| `Sell(volume, price, sl, tp, comment)` | Shortcut for sell | +| `BuyLimit/BuyStop/SellLimit/SellStop(...)` | Pending orders | +| `ResultRetcode()` | Check trade server return code | +| `ResultDeal()` | Get deal ticket after execution | + +### Position Queries + +```mql5 +// Iterate open positions (Hedging account) +uint total = PositionsTotal(); +for (uint i = 0; i < total; i++) { + string sym = PositionGetSymbol(i); + if (sym == _Symbol && PositionGetInteger(POSITION_MAGIC) == EA_MAGIC) { + double vol = PositionGetDouble(POSITION_VOLUME); + double sl = PositionGetDouble(POSITION_SL); + double tp = PositionGetDouble(POSITION_TP); + long type = PositionGetInteger(POSITION_TYPE); + } +} + +// Netting account — simpler +if (PositionSelect(_Symbol)) { + // position is selected +} +``` + +### Order Execution Pattern + +```mql5 +// Calculate price +double price = (signal == ORDER_TYPE_BUY) + ? SymbolInfoDouble(_Symbol, SYMBOL_ASK) + : SymbolInfoDouble(_Symbol, SYMBOL_BID); + +// Open with SL/TP +trade.PositionOpen(_Symbol, signal, lotSize, price, sl, tp, "EA Signal"); + +// Always check result +if (trade.ResultRetcode() != TRADE_RETCODE_DONE) { + Print("Trade failed: ", trade.ResultRetcode()); +} +``` + +### Hedging vs Netting + +```mql5 +bool IsHedging = ((ENUM_ACCOUNT_MARGIN_MODE) + AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); +``` + +- **Hedging**: multiple positions per symbol, must iterate and match Magic Number +- **Netting**: one position per symbol, use `PositionSelect()` + +## 3. Indicators and Multi-Timeframe + +### Built-in Indicator Handles + +```mql5 +// Moving Average +int handle = iMA(_Symbol, PERIOD_H1, 50, 0, MODE_SMA, PRICE_CLOSE); + +// RSI +int handle = iRSI(_Symbol, PERIOD_H1, 14, PRICE_CLOSE); + +// MACD +int handle = iMACD(_Symbol, PERIOD_H1, 12, 26, 9, PRICE_CLOSE); + +// Bollinger Bands +int handle = iBands(_Symbol, PERIOD_H1, 20, 0, 2.0, PRICE_CLOSE); +``` + +### Reading Indicator Values + +```mql5 +double buffer[]; +ArraySetAsSeries(buffer, true); +if (CopyBuffer(handle, 0, 0, 3, buffer) != 3) { + Print("No indicator data"); + return; +} +// buffer[0] = current bar value +// buffer[1] = previous bar value +``` + +### Multi-Timeframe Analysis + +```mql5 +// Higher timeframe trend +int h4_ma = iMA(_Symbol, PERIOD_H4, 50, 0, MODE_SMA, PRICE_CLOSE); + +// Entry timeframe signal +int h1_rsi = iRSI(_Symbol, PERIOD_H1, 14, PRICE_CLOSE); + +// In OnTick(): +double h4_val[], h1_val[]; +CopyBuffer(h4_ma, 0, 0, 1, h4_val); +CopyBuffer(h1_rsi, 0, 0, 1, h1_val); + +bool bullish = (SymbolInfoDouble(_Symbol, SYMBOL_BID) > h4_val[0]); +bool oversold = (h1_val[0] < 30); +``` + +### New Bar Detection + +```mql5 +datetime lastBarTime = 0; + +void OnTick() { + datetime currentBarTime = iTime(_Symbol, _Period, 0); + if (currentBarTime == lastBarTime) return; // not a new bar + lastBarTime = currentBarTime; + // New bar — run analysis here +} +``` + +## 4. Ticks and Bars + +### Timeseries Access + +Index 0 = current (unfinished) bar. Array is reverse-ordered. + +```mql5 +MqlRates rates[]; +ArraySetAsSeries(rates, true); +CopyRates(_Symbol, _Period, 0, 100, rates); + +// rates[0] = current bar +// rates[1] = previous bar +// rates[0].open, .high, .low, .close, .tick_volume, .time +``` + +### Tick Data + +```mql5 +MqlTick tick; +SymbolInfoTick(_Symbol, tick); +// tick.bid, tick.ask, tick.last, tick.volume, tick.time +``` + +### Key Functions + +| Function | Purpose | +|----------|---------| +| `CopyRates()` | Bulk OHLCV data | +| `CopyOpen/High/Low/Close()` | Individual price arrays | +| `CopyTime()` | Bar open times | +| `CopyBuffer()` | Indicator buffer values | +| `iBars()` | Bar count for symbol/period | +| `iBarShift()` | Bar index by time | +| `iTime()` | Bar open time by shift | +| `SymbolInfoTick()` | Current tick data | + +## 5. Risk Management and Lot Sizing + +### Fixed Percentage Risk + +```mql5 +double CalculateLotSize(double riskPercent, double slPoints) { + double accountBalance = AccountInfoDouble(ACCOUNT_BALANCE); + double riskAmount = accountBalance * riskPercent / 100.0; + + double tickValue = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); + double tickSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_SIZE); + double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT); + + if (tickValue == 0 || tickSize == 0 || slPoints == 0) return 0; + + double slMoneyPerLot = (slPoints * point / tickSize) * tickValue; + double lot = riskAmount / slMoneyPerLot; + + // Normalize to broker constraints + double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN); + double maxLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX); + double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP); + + lot = MathFloor(lot / lotStep) * lotStep; + lot = MathMax(lot, minLot); + lot = MathMin(lot, maxLot); + + return NormalizeDouble(lot, 2); +} +``` + +### Risk-to-Reward Ratio + +```mql5 +// Minimum 1:2 RR +double slDistance = MathAbs(price - sl); +double tpDistance = slDistance * 2; // 1:2 minimum +double tp = (orderType == ORDER_TYPE_BUY) ? price + tpDistance : price - tpDistance; +``` + +### Position Sizing Rules + +1. Never risk more than 1-2% per trade +2. Calculate lot size from risk amount and SL distance +3. Normalize to broker's lot step and min/max constraints +4. Account for spread when calculating SL distance + +## 6. Backtesting and Optimization + +### Strategy Tester + +The Strategy Tester is built into MT5. Key concepts: + +1. **Single Test**: run EA once with fixed parameters +2. **Optimization**: genetic algorithm searches parameter space +3. **Custom Criterion**: `OnTester()` returns optimization value + +### OnTester Handler + +```mql5 +double OnTester() { + // Called after each test pass + // Return value used as "Custom max" optimization criterion + + double profit = TesterStatistics(STAT_PROFIT); + double dd = TesterStatistics(STAT_BALANCE_DDREL_PERCENT); + double trades = TesterStatistics(STAT_TRADES); + double pf = TesterStatistics(STAT_PROFIT_FACTOR); + double sharpe = TesterStatistics(STAT_SHARPE_RATIO); + + // Minimum trade count filter + if (trades < 50) return 0; + + // Custom criterion: profit factor * (1 - max drawdown%) + return pf * (1.0 - dd / 100.0); +} +``` + +### Key Statistics + +| Stat | Description | +|------|-------------| +| `STAT_PROFIT` | Net profit/loss | +| `STAT_PROFIT_FACTOR` | Gross profit / gross loss | +| `STAT_BALANCE_DDREL_PERCENT` | Max balance drawdown % | +| `STAT_SHARPE_RATIO` | Sharpe ratio | +| `STAT_TRADES` | Number of trades | +| `STAT_PROFIT_TRADES` | Winning trades | +| `STAT_LOSS_TRADES` | Losing trades | +| `STAT_EXPECTED_PAYOFF` | Average profit per trade | +| `STAT_RECOVERY_FACTOR` | Profit / max drawdown | + +### Backtesting Workflow + +1. Code the EA with `OnTick()`, `OnInit()`, `OnDeinit()` +2. Add `OnTester()` for custom optimization criterion +3. In MT5: Strategy Tester → select EA → set symbol/timeframe/period +4. Choose "Open prices only" for speed, "Every tick" for accuracy +5. Run single test → check results +6. Run optimization → find best parameters +7. Validate with out-of-sample data + +### Automated Backtesting Loop + +``` +EA Development Cycle: + Code → Compile → Single Test → Check Results + ↓ + If promising → Optimize → Analyze Results + ↓ + If validated → Forward Test → Deploy + ↓ + Monitor → Collect Data → Refine → Repeat +``` + +## 7. Event Handlers Reference + +| Handler | When Called | Use Case | +|---------|-----------|----------| +| `OnInit()` | EA/indicator starts | Initialize handles, variables | +| `OnDeinit()` | EA/indicator stops | Cleanup, release handles | +| `OnTick()` | New tick received | EA main logic | +| `OnTimer()` | Timer event | Periodic operations | +| `OnTrade()` | Trade event | React to trade changes | +| `OnTradeTransaction()` | Trade transaction | Detailed trade tracking | +| `OnChartEvent()` | Chart interaction | GUI buttons, objects | +| `OnCalculate()` | Indicator calculation | Indicator main logic | +| `OnTester()` | Test complete | Custom optimization criterion | +| `OnTesterInit()` | Optimization start | Setup for optimization | +| `OnTesterPass()` | Each optimization pass | Log intermediate results | + +## 8. Common Pitfalls + +1. **Always check `ResultRetcode()`** after `PositionOpen()` — success != execution +2. **Use `SetExpertMagicNumber()`** to distinguish your EA's trades +3. **Normalize prices** with `SymbolInfoInteger(_Symbol, SYMBOL_DIGITS)` +4. **Check `Bars() > N`** before trading to ensure enough history +5. **Use `ArraySetAsSeries(true)`** for timeseries arrays (index 0 = latest) +6. **Release indicator handles** in `OnDeinit()` with `IndicatorRelease()` +7. **Don't trade on `OnInit()`** — wait for first `OnTick()` +8. **Account type matters**: Hedging requires iterating positions, Netting uses select +9. **Spread varies**: use `SymbolInfoInteger(_Symbol, SYMBOL_SPREAD)` for live spread +10. **Timer in tester**: use `EventSetTimer()` in `OnInit()`, not hardcoded delays + +## 9. Quick Reference — EA Skeleton + +```mql5 +//+------------------------------------------------------------------+ +//| MyExpertAdvisor.mq5 | +//+------------------------------------------------------------------+ +#property copyright "Your Name" +#property link "" +#property version "1.00" + +#include + +input double RiskPercent = 1.0; // Risk % per trade +input int Slippage = 10; // Max slippage in points +input int MagicNumber = 12345; // EA magic number + +#define EA_MAGIC MagicNumber + +CTrade trade; +bool IsHedging; +datetime lastBarTime = 0; + +//+------------------------------------------------------------------+ +int OnInit() { + IsHedging = ((ENUM_ACCOUNT_MARGIN_MODE) + AccountInfoInteger(ACCOUNT_MARGIN_MODE) == ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); + + trade.SetExpertMagicNumber(EA_MAGIC); + trade.SetMarginMode(); + trade.SetTypeFillingBySymbol(Symbol()); + trade.SetDeviationInPoints(Slippage); + + return INIT_SUCCEEDED; +} + +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) { + // Cleanup +} + +//+------------------------------------------------------------------+ +void OnTick() { + // New bar check + datetime barTime = iTime(_Symbol, _Period, 0); + if (barTime == lastBarTime) return; + lastBarTime = barTime; + + // Analysis and trading logic here + // ... +} + +//+------------------------------------------------------------------+ +double OnTester() { + // Custom optimization criterion + double trades = TesterStatistics(STAT_TRADES); + if (trades < 30) return 0; + return TesterStatistics(STAT_PROFIT_FACTOR); +} +``` + +## 10. References + +### In this skill + +- `references/book/` — Programming book (learning path, 581 pages) + - `00-intro/` — Introduction and IDE + - `01-basis/` — Language fundamentals + - `02-oop/` — Object-oriented programming + - `03-common/` — Common functions (strings, files, math) + - `04-applications/` — Charts, indicators, objects, events + - `05-automation/` — Trading, symbols, tester + - `06-advanced/` — Resources, SQLite, Python, OpenCL +- `references/docs/` — API reference (4135 pages) + - `19-trading/` — Trading functions (OrderSend, PositionGet, etc.) + - `16-series/` — Timeseries access (CopyRates, CopyBuffer, etc.) + - `26-indicators/` — Built-in indicators (iMA, iRSI, iMACD, etc.) + - `24-customind/` — Custom indicator creation + - `13-event-handlers/` — Event handlers (OnTick, OnTester, etc.) + - `34-standardlibrary/` — Standard library (CTrade, CPositionInfo, etc.) + +### External + +- [MQL5 Reference](https://www.mql5.com/en/docs) +- [MQL5 Book](https://www.mql5.com/en/book) +- [Strategy Tester Guide](https://www.mql5.com/en/terminal/strategytester) diff --git a/skills/mql5/references/book/00-intro/0001-intro.md b/skills/mql5/references/book/00-intro/0001-intro.md new file mode 100644 index 0000000..7b67f7b --- /dev/null +++ b/skills/mql5/references/book/00-intro/0001-intro.md @@ -0,0 +1,60 @@ +# Introduction to MQL5 and development environment + +One of the most important changes in MQL5 in its reincarnation in MetaTrader 5 is that it supports the object-oriented programming (OOP) concept. At the time of its appearance, the preceding MQL4 (the language of MetaTrader 4) was conventionally compared to the C programming language, while it is more reasonable to liken MQL5 to C++. In all fairness, it should be noted that today all OOP tools that initially had only been available in MQL5 were transferred into MQL4. However, users who scarcely know programming still perceive OOP as something too complicated. + +In a sense, this book is aiming at making complex things simple. It is not to replace, but to be added to the MQL5 Language Reference that is supplied with the terminal and also available on the mql5.com website. + +In this book, we are going to consistently tell you about all the components and techniques of programming in MQL5, taking baby steps so that each iteration is clear and the OOP technology gradually unlocks its potential that is especially notable, as with any powerful tool, when it is used properly and reasonably. As a result, the developers of MQL programs will be able to choose a preferred programming style suitable for a specific task, i.e., not only the object-oriented but also the 'old' procedural one, as well as use various combinations of them. + +Users of the trading terminal can be conveniently classified into "programmers" (those who have already some experience in programming in at least one language) and "non-programmers" ("pure" traders interested in the customization capacity of the terminal using MQL5). The former ones can optionally skip the first and the second parts of this book describing the basic concepts of language and immediately start learning about the specific APIs (Application Programming Interfaces) embedded in MetaTrader 5. For the latter ones, progressive reading is recommended. + +Among the category of "programmers," those knowing C++ have the best advantages, since MQL5 and C++ are similar. However, this "medal" has its reverse side. The matter is that MQL5 does not completely match with C++ (especially when compared to the recent standards). Therefore, attempts to write one structure or another through habit "as on pluses" will frequently be interrupted by unexpected errors of the compiler. Considering specific elements of the language, we will do our best to point out these differences. + +Technical analysis, executing trading orders, or integration with external data sources — all these functions are available to the terminal users both from the user interface and via software tools embedded in MQL5. + +Since MQL5 programs must perform different functions, there are some specialized program types supported in MetaTrader 5. This is a standard technique in many software systems. For example, in Windows, along with usual windowing programs, there are command-line-driven programs and services. + +The following program types are available in MQL5: + +- Indicators — programs aimed at graphically displaying data arrays computed by a given formula, normally based on the series of quotes; +- Expert Advisors — programs to automate trading completely or partly; +- Scripts — programs intended for performing one action at a time; and +- Services — programs for performing permanent background actions. + +We will discuss the purposes and special features of each type in detail later. It is important to note now that they all are created in MQL5 and have much in common. Therefore, we will start learning with common features and gradually get to know about the specificity of each type. + +The essential technical feature of MetaTrader consists in exerting the entire control in the client terminal, while commands initiated in it are sent to the server. In other words, MQL-based applications can only work within the client terminal, most of them requiring a 'live' connection to the server to function properly. No applications are installed on the server. The server just processes the orders received from the client terminal and returns the changes in the trading environment. These changes also become available to MQL5 programs. + +Most types of MQL5 programs are executed in the chart context, i.e., to launch a program, you should 'throw' it onto the desired chart. The exception is only a special type, i.e., services: They are intended for background operation, without being attached to the chart. + +We recall that all MQL5 programs are inside the working MetaTrader 5 folder, in the nested folder named /MQL5/, where is, respectively: + +- Indicators +- Experts +- Scripts +- Services + +Based on the MetaTrader 5 installation technique, the path to the working folder can be different (particularly, with the limited user rights in Windows, in a normal mode or portable). For example, it can be: + +``` +C:/Program Files/MetaTrader 5/ + +``` + +or + +``` +C:/Users//AppData/Roaming/MetaQuotes/Terminal// + +``` + +The user can get to know where this folder is located exactly by executing the File -> Open data catalog command (it is available in both terminal and editor). Moreover, when creating a new program, you don't need to think of looking up the correct folder due to using the MQL Wizard embedded in the editor. It is called for by the File -> New command and allows selecting the required type of the MQL5 program. The relevant text file containing a source code template will be created automatically where necessary upon completing the Master and then opened for editing. + +In the MQL5 folder, there are other nested folders, along with the above ones, and they are also directly related to MQL5 programming, but we will refer to them later. + +``` +MQL5 Programming for Traders — Source Codes from the Book. Part 1 + +Examples from the book are also available in the public project \MQL5\Shared Projects\MQL5Book + +``` diff --git a/skills/mql5/references/book/00-intro/0002-intro-edit-compile-run.md b/skills/mql5/references/book/00-intro/0002-intro-edit-compile-run.md new file mode 100644 index 0000000..2202d35 --- /dev/null +++ b/skills/mql5/references/book/00-intro/0002-intro-edit-compile-run.md @@ -0,0 +1,33 @@ +# Editing, compiling, and running programs + +All MetaTrader 5 programs are compilable. That is, a source code written in MQL5 must be compiled to obtain the binary representation that will be exactly the one executed in the terminal. + +Programs are edited and compiled using MetaEditor. + +![Editing an MQL program in MetaEditor](pics/me_edit_en.png) + +Editing an MQL program in MetaEditor + +Source code is a text written according to the MQL5 rules and saved as a file having the extension of mq5. The file containing a compiled program will have the same name, while its extension will be ex5. + +In the simplest case, one executable file corresponds with one file containing the source code; however, as we will see later, coding complex programs frequently requires splitting the source code into multiple files: The main one and some supporting ones that are enabled from the main file in a special manner. In this case, the main file must still have the extension of mq5, while those enabled from it must have the extension of mqh. Then statements from all source files will get into the executable file being generated. Thus, multiple files containing the source code may be the starting point for creating one executable file/program. All this mentioned here to complete the picture is going to be presented in the second part of the book. + +We will use the term MQL5 syntax to denote the set of all rules that allow constructing programs in MQL5. Only the strict adherence to the syntax allows coding programs compatible with the compiler. In fact, teaching to code consists of sequentially introducing all the rules of a particular language that is MQL5, in our case. And this is the main purpose of this book. + +To compile a source code, we can use the command MetaEditor File -> Compile or just press F7. However, there are some other, special methods to compile – we will discuss them later. Compiling is accompanied by displaying the changing status in the editor log (where an MQL5 program consists of multiple files containing the source code, and enabling each file is marked in a single log line). + +![Compiling an MQL5 program in MetaEditor](pics/me_compile_en.png) + +Compiling an MQL5 program in MetaEditor + +An indication of a successful compilation is zero errors ("0 errors"). Warnings do not affect the compilation results, they just inform on potential issues. Therefore, it is recommended to fix them on the same basis as errors (we will tell you later how to do that). Ideally, there should not be any warnings ("0 warnings"). + +Upon the successful compilation of an mq5 file, we get a same-name file with the extension of ex5. MetaTrader 5 Navigator displays as a tree all executable ex5 files located in folder MQL5 and its subfolders, including the one just compiled. + +![MetaTrader 5 Navigator with a compiled MQL5 program](pics/mt_navex_en.png) + +MetaTrader 5 Navigator with a compiled MQL5 program + +Ready programs are launched in the terminal using any methods familiar to the user. For instance, any program, other than a service, can be dragged with the mouse from Navigator to the chart. We will talk about the features of services separately. + +Besides, developers often need the program to be executed in the debugging mode to find what causes the errors. There are multiple special commands for this purpose, and we will refer to them in [Bug fixing and debugging](/en/book/intro/errors_debug). diff --git a/skills/mql5/references/book/00-intro/0003-intro-mql-wizard.md b/skills/mql5/references/book/00-intro/0003-intro-mql-wizard.md new file mode 100644 index 0000000..2bf279d --- /dev/null +++ b/skills/mql5/references/book/00-intro/0003-intro-mql-wizard.md @@ -0,0 +1,55 @@ +# MQL Wizard and program draft + +Here we will consider the simplest MQL program that does not really do anything. It is aimed at introducing the process of writing a source code in the editor, compiling it, and launching it in the terminal. Following the steps below independently, you will make sure that programming is available to casual users and start adapting to the integrated development environment of MQL5 programs. It will always be needed for consolidating the material covered. + +The simplest MQL5 programs are scripts. Therefore, it is a script that we are going to try and create. For this purpose, let's start MQL5 Wizard (File -> New). In the first step, we will select Script in the list of types and press Next: + +![Creating a script using MQL Wizard. Step 1](pics/wizard_start_en.png) + +Creating a script using MQL Wizard. Step 1 + +In the second step, we will introduce the script name in the Name field, having added it after the default folder mentioned above and a backslash: "Scripts\". For instance, let's name the script "Hello" (that is, the Name field will contain the line: "Scripts\Hello") and, without changing anything else, press Finish. + +![Creating a script using MQL Wizard. Step 2](pics/wizard_script_name_params_en.png) + +Creating a script using MQL Wizard. Step 2 + +As a result, the Wizard will create a file named Hello.mq5 and open it for editing. The file is located in folder MQL5/Scripts (standard location for scripts) because we have used the default folder; however, we could add any sub-folder or even a sub-folder hierarchy. For instance, if we write "Scripts\Exercise\Hello" in the Name field at Wizard Step 1, then the Exercise sub-folder will be created in the Scripts folder automatically, and the file Hello.mq5 will be located in that sub-folder. + +All examples from this book will be located in the MQL5Book folders inside catalogs allocated for the MQL programs of relevant types. This is necessary to facilitate installing the examples into your working copy of the terminal and rule out any name conflicts with other MQL programs you have already installed. + +  + +For example, file Hello.mq5 delivered as part of this book is located in MQL5\Scripts\MQL5Book\p1\, where p1 means Part 1 this example relates to. + +The resulting template of script Hello.mq5 contains the following text: + +``` +//+------------------------------------------------------------------+ +//|                                                        Hello.mq5 | +//|                                  Copyright 2021, MetaQuotes Ltd. | +//|                                             https://www.mql5.com | +//+------------------------------------------------------------------+ +  +#property copyright "Copyright 2021, MetaQuotes Ltd." +#property link      "https://www.mql5.com" +#property version   "1.00" +  +//+------------------------------------------------------------------+ +//| Script program start function                                    | +//+------------------------------------------------------------------+ +void OnStart() +{ +} +  +//+------------------------------------------------------------------+ + +``` + +It is this script that is shown in the preceding screenshots of MetaEditor and MetaTrader 5. + +All strings starting with "//" are the comments and do not affect the program intent. They are neither processed by the compiler nor executed by the terminal. They are only used to exchange explanatory information among developers or to visually emphasize the code parts to enhance the text readability. For instance, in this template, the file starts with a block containing a comment where the script name and the author's copyright are expected to be specified. The second block of comments is the heading for the main function of the script — it is referred to in more detail below. Finally, the last comment string visually emphasizes the file end. + +Three strings starting with a special directive, #property, provide the compiler with some attributes it builds into the program in a special manner. In our case, they are not important so far and can even be deleted. The specific directories are available to each MQL program type — we will know about them as soon as we proceed to learning the particular program types. + +The main part of the script, where we are going to describe the essence of the program actions, is represented by the OnStart function. Here we have to learn the concepts of 'code block' and 'function'. diff --git a/skills/mql5/references/book/00-intro/0004-intro-statement-blocks.md b/skills/mql5/references/book/00-intro/0004-intro-statement-blocks.md new file mode 100644 index 0000000..d85d95b --- /dev/null +++ b/skills/mql5/references/book/00-intro/0004-intro-statement-blocks.md @@ -0,0 +1,73 @@ +# Statements, code blocks, and functions + +Thus, in the script generated by the Wizard, the OnStart function appears as follows: + +``` +void OnStart() +{ +} + +``` + +It is exactly our first subject matter within the context of programming in MQL5. Here again, we immediately encounter unknown concepts and character sequences. To explain them, we shall make a short digression. + +A program must usually implement the following typical stages when running: + +- Defining variables, i.e., named cells in the computer memory to store data; +- Organizing the source data input; +- Processing the data — an applied algorithm; and +- Organizing the output of results. + +All these stages are not necessary in terms of maintaining the syntactic correctness of the program. For example, if we create a program that computes the product of "2*2", it obviously does not need any input data, because numbers necessary for multiplying are integrated in the program text. Moreover, since 2 and 2 are constant values in this expression, no named cells (variables) are required in the program. Since we know it anyway what twice two is, we don't really need to communicate the product number. Such a program would lack any real function, of course. However, it would be absolutely correct from a technical point of view. + +More interestingly, the program may contain no statements on processing. Our script template specifically represents a sample 'null' program. But what is the above text fragment? + +In his day, Niklaus Wirth, one of the big names in programming, gave a simple generalized definition of programming as a symbiosis of algorithms and data structures. + +"Algorithm" shall mean a sequence of statements of a particular programming language. A statement is a kind of sentence, i.e., a completed utterance, articulated in a programming language according to its syntax rules. The name "statement" itself suggests that it is perceived by computers as a guide to operations. In other words, statements describe when and how the required applied data structures shall be processed. This is exactly why the interpenetration of algorithms and data structures allows putting the author's ideas into practice. + +Unfortunately, in most practical tasks, the number of statements is so large that they must be systematized somehow for the human to recognize and control the program behavior. + +Here too, the divide-and-conquer algorithm comes to help, which is used practically everywhere in programming and in different guises. We will learn all of them as we continue in this book, now just noting the essence. + +As known, the algorithm reduces to dividing a large complex task into smaller and simpler ones. Here, we can compare this process with constructing a house or assembling a spacecraft. Both "products" consist of multiple different modules that, in turn, consist of components, and the latter ones of even smaller parts, etc. + +Extending this similarity to algorithms, we can say that statements are small parts, while the entire program is a house/spacecraft. Therefore, we need structural blocks sized intermediately. + +This is why it is customary, when implementing algorithms, to combine logically related statements into larger named fragments, the functions. In the required places of the program, we can address the function by its name (call it) and doing so, ask the computer to execute all statements contained inside the function. The entire program is, in fact, the largest external block and therefore, it can also be presented by the function, from which smaller functions are called or statements are executed immediately if they are not many. Now we're approaching the OnStart function. + +Name OnStart is reserved in scripts to denote the ultimate function that is called by the terminal itself as a response to the user's actions when the user launches the script using the context menu command or dragging the mouse over the chart. Thus, the preceding fragment of the code defines the function OnStart that predetermines the behavior of our entire script. + +Those who know programming in other languages, such as C, C++, Rust, or Kotlin, can notice the similarity of this function with the function main – the core point of entering into the program. + +Any script must contain the function OnStart. Otherwise, the compilation may finish with an error. + +Empty function OnStart, as ours, starts being executed by the terminal (as soon as the script is launched in any manner) and immediately finishes its operation. Strictly speaking, there is no applied algorithm in our script yet, but there is already a stub function to add it. + +In other types of MQL programs, there are also special functions to be defined by the programmer in their code. We will get into the specific features in the relevant parts of the book. + +We will consider the function definition syntax in detail in the second part of this book. For a hands-on review of it, it is sufficient to mention the following basic essentials to understand the description of OnStart. + +Since functions are usually intended for obtaining an applicable result, the characteristics of the expected value are described in a special manner in their definition: What data types should be obtained and whether the data is even necessary. Some functions can perform actions that do not require returning the value. For example, a function can be intended for changing the settings of the current chart or to send push notifications when the predefined drawdown level is reached on the account. All this can be programmed by the statements in the function, and it does not create any new data (reasonable to be returned to any other parts of the program). + +In our case, the situation is similar: As the main function of the script, OnStart could return its result to the external environment only (directly into the terminal) when completed, but this would not affect the operation of the script itself in any way (because it has already finished off). + +That is exactly why, before the OnStart function name, there is the word void that informs the compiler that the result is not important to us (void means emptiness). void is one of many procedure words reserved in MQL5. The compiler knows the meanings of all reserved words, and it is guided by them in reviewing the source code. Particularly, a programmer may use reserved words to define new terms for the compiler, such as the function OnStart itself. + +Parentheses after the name are integral to the description of any function: They may enclose the list of function parameters. For instance, if we were writing a function taking a square of a number, we would have to provide it with one parameter for that number. Then we could call this function from any part of the program, having sent one argument over it, i.e., the specific value for the parameter. We will see later how to describe the list of parameters; it is not in this current example. This requirement is posed on the function OnStart for it is called by the terminal itself, and it never sends anything to this function as parameters. + +At last, braces are used to mark the beginning and the end of the block containing statements. Immediately following the function name string, such a block will contain a set of operations performed by this function. It is also named the function body. In this case, there is nothing inside the braces. Therefore, the script template does not do anything. + +The above sequence of word void, name OnStart, an empty list of parameters, and an empty code block defines the least, empty implementation of the function OnStart for the compiler. Later, adding statements into the function body, we will extend the definition of function OnStart. + +Having executed the Compile command, we will make sure that the script can be successfully compiled, and that the ready program appears in the Navigator of the terminal in the folder Scripts/MQL5Book/p1. This results from the fact that, on the disk in the relevant folder, there is now the file of Hello.ex5. It can easily be checked in any file manager. + +We can run the script on a chart, but the only confirmation of its execution will be the entries in the terminal log (tab Log in the Tools window; not to be mixed with the toolbar): + +``` +Scripts        script Hello (EURUSD,H1) loaded successfully +Scripts        script Hello (EURUSD,H1) removed + +``` + +That is, the script is loaded, the control is sent to the function OnStart, but immediately returned to the terminal because the function does not do anything, and after that, the terminal unloaded the script from the chart. diff --git a/skills/mql5/references/book/00-intro/0005-intro-first-program.md b/skills/mql5/references/book/00-intro/0005-intro-first-program.md new file mode 100644 index 0000000..835eee7 --- /dev/null +++ b/skills/mql5/references/book/00-intro/0005-intro-first-program.md @@ -0,0 +1,71 @@ +# First program + +Let's try to add to the script something simple but illustrative to demonstrate its operation. Let's rename the modified script as HelloChart.mq5. + +In many programming textbooks, the initial example prints the sacramental "Hello, world". In MQL5, a similar greeting could appear as follows: + +``` +void OnStart() +{ +  Print("Hello, world"); +} + +``` + +But we will make it more informative: + +``` +void OnStart() +{ +  Print("Hello, ", Symbol()); +} + +``` + +Thus, we have added only one string with some language structures. + +Here, Print is the name of the function embedded in the terminal and intended to display messages in the Expert Advisors log (tab Expert Advisors in the Tools window; despite its name Expert Advisors, the tab collects messages from MQL programs of all types). Unlike the function OnStart that we are defining independently, the Print function is defined for us in advance and forever. Print is one of many embedded functions constructing the MQL5 API (application programming interface). + +The new line in our code denotes the statement to call the Print function sending into it the list of arguments (in parentheses) that will be printed in the log. Arguments in the list are separated by commas. In this case, there are two arguments: Line "Hello " and call for another embedded function, Symbol, that returns the name of the active instrument on the current chart (the value obtained from it will immediately get into the list of arguments of function Print, into the location from which the Symbol function has been called). + +The Symbol function does not have any parameters and, therefore, nothing is sent into it inside parentheses. + +For instance, if the script is located on the "EURUSD" chart, then calling the function Symbol() will return "EURUSD" and, in terms of the program being executed, the statement regarding calling the function Print will have a new look: Print("Hello, ", "EURUSD"). From a user's point of view, of course, all these calls for functions and the dynamic substitution of intermediary results are smooth and immediate. However, for a programmer, it is important to fully realize how the program is executed step by step to avoid logical errors and achieve strict compliance with the plan conceived. + +The "Hello " line in double quotation marks is referred to as the literal, i.e., a fixed sequence of characters perceived by the computer as a text, as it is (as it is introduced in the source code of the program). + +Thus, the printing statement above must print the two arguments one by one in the log, which should result in actually joining the two lines and obtaining "Hello, EURUSD". + +Importantly, the comma inside the quotation marks will be printed in the log as a part of the line and is not processed in any special manner. Unlike that, the comma that is placed after the closing quotation mark and before calling Symbol() is the separating character in the argument list, i.e., affects the program behavior. If the first comma is omitted, the program will not lose its correctness, although it will print the word "Hello" without a comma after it. However, if the second comma is omitted, the program will stop being compiled, since the syntax of the function argument list will be broken: All values in it (in our case, these are two lines) must be separated by commas. + +The compiler error will appear as follows: + +``` +'Symbol' - some operator expected        HelloChart.mq5        16        19 + +``` + +The compiler 'complains' of the lack of something before mentioning Symbol. This will break the compilation, and the executable file of the program is not created. Therefore, we will put the comma back in place. + +This example shows us how important it is to strictly follow the syntax of the language. The same characters can work differently, being in different parts of the program. Thus, even a small omission may be critical. For instance, note the semicolon at the end of the line calling Print. The semicolon means the end of the statement here. If we forget to put it, strange compiler errors may occur. + +To see this, we will try to remove this semicolon and re-compile the script. This results in obtaining new errors with the description of the problem and its place in the source code. + +![Compilation errors in the MetaEditor log](pics/me_error_en.png) + +Compilation errors in the MetaEditor log + +``` +'}' - semicolon expected        HelloChart.mq5        17        1 +'}' - unexpected end of program        HelloChart.mq5        17        1 + +``` + +The first error explicitly specifies the absence of the semicolon expected by the compiler. The second error is propagated: The closing brace signaling the end of the program had been detected before the current statement ended. In the compiler's opinion, it continues, because it has not encountered the semicolon yet. It is obvious how to fix the errors: The semicolon must be placed back in the right position in the statement. + +Let's compile and launch the fixed script. Although it is executed very quickly and removed from the chart practically immediately and a record confirming the script operation appears in the Experts log. + +``` +HelloChart (EURUSD,H1)        Hello, EURUSD + +``` diff --git a/skills/mql5/references/book/00-intro/0006-intro-types-and-values.md b/skills/mql5/references/book/00-intro/0006-intro-types-and-values.md new file mode 100644 index 0000000..0f41bbe --- /dev/null +++ b/skills/mql5/references/book/00-intro/0006-intro-types-and-values.md @@ -0,0 +1,40 @@ +# Data types and values + +Along with calling the embedded function Symbol, we could also use our own function that we have defined in the source code. Suppose we would like to print in the log not just "Hello", but different greetings depending on the time of day. We will determine the time of day accurate to hours: 0-8 is morning, 8-16 is afternoon, and 16-24 is evening. + +It is logical to suggest that the definition structure of the new function must be similar to that of the function OnStart already familiar to us. However, its name must be unique, i.e., it should not duplicate the names of other functions or reserved words. We will study the list of these words further in this textbook, while now luckily suggesting that the word Greeting can be used as a name. + +Like the Symbol function, this function must return a string; this time, however, the string must be one of the following phrases, depending on the time of day: "Good morning", "Good afternoon", or "Good evening". + +Guided by common sense, we are using the common concept of string here. Apparently, it is familiar to the compiler, because we saw how it had generated a program printing the predefined text. Thus, we have smoothly approached to the concept of types in the programming language, one of the types being a string, i.e., a sequence of characters. + +In MQL5, this type is described by the keyword string. This is the second type we know, the first one was void. We have already seen a value of this type, without knowing it was that: It is the literal "Hello, ". When we just insert a constant (particularly, something like a quoted text) into the source code, its type description is not required: defines the correct type automatically. + +Using the OnStart function description as a sample, we can suggest how the function Greeting should appear for a first approximation. + +``` +string Greeting() +{ +} + +``` + +This text indicates our intention to create the Greeting function, which can return an arbitrary value of the string type. However, for the function to really return something, it is necessary to use a special statement with the return operator. It is one of many MQL5 operators: We will explore them all later. If the function has a return value type other than void, it must contain the operator return. + +Particularly, to return the former greeting string "Hello, " from the function, we should write: + +``` +string Greeting() +{ +  return "Hello, "; +} + +``` + +Operator return stops the function execution and sends out what is to the right of it, as a result. "Out" hides the source code fragment, from which the function was called. + +We have not explored all the options for writing expressions that could form an arbitrary string. However, the simplest instance with the quoted text is transferred here without any changes. It is important that the return value type coincides with the function type, as in our case. At the end of the statement, we put a semicolon. + +However, we wanted to generate different greetings depending on the time of day. Therefore, the function must have an hour-defining parameter that can take values ranging from 0 through 23. Obviously, the hour number is an integer, i.e., a number that has no fractional part. It is clear that the time does not stop within an hour, and minutes are counted in it, the number of minutes being an integer, too. Then again, it is pointless to determine the time of day accurately to a minute. Therefore, we will limit ourselves to choosing the greeting by the hour number only. + +For integer values, there is a special type int in MQL5. This value should be sent to the function Greeting from another place in the program, from which this function will be called. Here we have first faced the necessity of describing a named memory cell, that is, a variable. diff --git a/skills/mql5/references/book/00-intro/0007-intro-variables-and-identifiers.md b/skills/mql5/references/book/00-intro/0007-intro-variables-and-identifiers.md new file mode 100644 index 0000000..e2378b4 --- /dev/null +++ b/skills/mql5/references/book/00-intro/0007-intro-variables-and-identifiers.md @@ -0,0 +1,27 @@ +# Variables and identifiers + +A variable is a memory cell having a unique name (to be referred to without any errors), which can store the values of a certain type. This ability is ensured by the fact that the compiler allocates for the variable just enough memory that is required for it in the special internal format: Each type is sized and has a relevant memory storing format. More details on this are given in Part 2. + +Basically, there is a stricter term, identifier, in the program, which term is used for the names of variables, functions, and many other entities to be learned later herein. Identifier follows some rules. In particular, it may only contain Latin characters, numbers, and underscores; and it may not start with a number. This is why the word 'Greeting' chosen for the function earlier meets these requirements. + +Values of a variable can be different, and they can be changed using special statements during the program execution. + +Along with its type and name, a variable is characterized by the context, i.e., an area in the program, where it is defined and can be used without any errors of compiler. Our example will probably facilitate understanding this concept without any detailed technical reasoning in the beginning. + +The matter is that a particular instance of a variable is the function parameter. The parameter is intended for sending a certain value into the function. Hereof it is obvious that the code fragment, where there is such a variable, must be limited to the body of the function. In other words, the parameter can be used in all statements inside the function block, but not outside. If the programming language allowed such liberties, this would become a source of many errors due to the potential possibility to 'spoil' the function inside from a random program fragment that is not related to the function. + +In any case, it is a slightly simplified definition of a variable, which is sufficient for this introductory section. We will consider some finer nuances later. + +Hence, let's generalize our knowledge of variables and parameters: They must have type, name, and context. We write the first two characteristics in the code explicitly, while the last one results from the definition location. + +Let's see how we can define the parameter of the hour number in the Greeting function. We already know the desired type, it's int, and we can logically choose the name: hour. + +``` +string Greeting(int hour) +{ +  return "Hello, "; +} + +``` + +This function will still return "Hello," whatever the hour. Now we should add some statements that would select different strings to return, based on the value of parameter hour. Please remember that there are three possible function response options: "Good morning", "Good afternoon", and "Good evening". We could suppose that we need 3 variables to describe these strings. However, it is much more convenient to use an array in such cases, which ensures a unified method of coding algorithms with access to elements. diff --git a/skills/mql5/references/book/00-intro/0008-intro-init-assign-express.md b/skills/mql5/references/book/00-intro/0008-intro-init-assign-express.md new file mode 100644 index 0000000..2f41266 --- /dev/null +++ b/skills/mql5/references/book/00-intro/0008-intro-init-assign-express.md @@ -0,0 +1,111 @@ +# Assignment and initialization, expressions and arrays + +An array is a named set of same-type cells that are located in memory contiguously, each being accessible by its index. In a sense, it is a composite variable characterized by a common identifier, type of values stored, and quantity of numbered elements. + +For instance, an array of 5 integers can be described as follows: + +``` +int array[5]; + +``` + +Array size is specified in square brackets after the name. Elements are numbered from 0 through N-1, where N is the array size. They are accessed, i.e., the values are read, using a similar syntax. For example, to print the first element of the above array into the log, we could write the following statement: + +``` +Print(array[0]); + +``` + +Please note that index 0 corresponds to the very first element. To print the last element, the statement would be replaced with the following: + +``` +Print(array[4]); + +``` + +It is supposed, of course, that before printing an element of the array, a useful value has once been written into it. This record is made using a special statement, i.e., assignment operator. A special feature of this operator is the use of the symbol '=', to the left of which the array element (or variable) is specified, in which the record is made, while to the right of it the value to be recorded or its 'equivalent' is specified. Here, 'equivalent' hides the language ability to compute expressions of arithmetic, logic, and other types (we will learn them in Part 2). Syntax of the expressions is mostly similar to the rules of writing the equations learned in school-time arithmetic and algebra. For example, operations of addition ('+'), subtraction ('-'), multiplication ('*'), and division ('/') can be used in an expression. + +Below are examples of operators to fill out some elements of the array above. + +``` +array[0] = 10;                       // 10 +array[1] = array[0] + 1;             // 11 +array[2] = array[0] * array[1] + 1;  // 111 + +``` + +These statements demonstrate various methods of assignment and constructing expressions: In the first string, literal 10 is written into element array[0], while in the second and third lines, the expressions are used, computing which leads to obtaining the results specified for visual clarity in comments. + +Where array elements (or variables, in a general case) are involved in an expression, the computer reads their values from memory during program execution and performs the above operations with them. + +It is necessary to distinguish the use of variables and array elements to the left of and to the right of the '=' character in the assignment statement: On the left, there is a 'receiver' of the processed data (it is always single), while on the right, there are the 'sources' of initial data for computing (there can be many 'sources' in an expression, like in the last string of this example, where the values of elements array[0] and array[1] are multiplied together). + +In our examples, the '=' character was used to assign the values to the elements of a predefined array. However, it is sometimes convenient to assign initial values to variables and arrays immediately upon defining them. This is called initialization. The '=' character is used for it, too. Let's consider this syntax in the context of our applied task. + +Let's describe the array of strings with the greeting options inside the function Greeting: + +``` +string Greeting(int hour) +{ +  string messages[3] = {"Good morning", "Good afternoon", "Good evening"}; +  return "Hello, "; +} + +``` + +In the statement added, not only the messages array with 3 elements is defined, but also its initialization, i.e., filling with the desired initial values. Initialization highlights the '=' character upon variable/array name and type description. For a variable, it is necessary to specify only one value after '=' (without braces), while for an array, as we can see, we can write several values separated by commas and enclosed in braces. + +Do not confuse initialization with assignment. The former is specified in defining a variable/array (and is made once), while the latter occurs in specific statements (the same variable or array element can be assigned with different values over and over again). Array elements can only be assigned separately: MQL5 does not support assigning all elements at a time, as is the case with initialization. + +The messages array, being defined inside the function, is available only inside it, like the parameter hour. Then we will see how we can describe variables available throughout the program code. + +How shall we transform the incoming value of hour with the hour number into one of the three elements? + +Recall that, according to our idea, hour can have values from 0 through 23. If we divide it by 8 exactly, we will obtain the values from 0 through 2. For instance, dividing 1 by 8 will give us 0, and 7 by 8 will give 0 (in exact division, the fractional part is neglected). However, dividing 8 by 8 is 1, so all numbers through 15 will give us 1 when divided by 8. Numbers 16-23 will correspond with the division result of 2. Integers 0, 1, and 2 obtained shall be used as indexes to read the messages array element. + +In MQL5, operation '/' allows computing the exact division for integers. + +Expression to obtain the division results is similar to those we have recently considered for the array, just the parameter hour and operation '/' must be used. We will use the following statement as a demonstration of a possible implementation of the hour transformation into the element index: + +``` +int index = hour / 8; + +``` + +Here, a new integer variable, index, is defined and initialized by the value of the above expression. + +However, we can omit saving the intermediate value in the index variable and immediately transfer this expression (to the right of '=') inside square brackets, where the array element number is specified. + +Then in the statement with operator return, we can extract the relevant greeting as follows: + +``` +string Greeting(int hour) +{ +  string messages[3] = {"Good morning", "Good afternoon", "Good evening"}; +  return messages[hour / 8]; +} + +``` + +The function is more or less ready. After a couple of sections, we will make some corrections, though. So far, let's save the project in a file under another name, GoodTime0.mq5, and try to call our function. For this reason, in OnStart, we will use the call for Greeting inside the Print call. + +``` +void OnStart() +{ +  Print(Greeting(0), ", ", Symbol()); +} + +``` + +We have saved the separating comma (put inside lateral "Hello, ") between the greeting and the instrument name. Now there are three arguments in the Print function call: The first and the last ones will be computed on the fly using calls, respectively, of functions Greeting and Symbol, while the comma will be sent for printing as it is. + +So far, we are sending the constant '0' into the function Greeting. It is its value that will get into the hour parameter. Having compiled and launched the program, we can make sure that it prints the desired text in the log. + +``` +GoodTime0 (EURUSD,H1)        Good morning, EURUSD + +``` + +However, in practice, greetings must be selected dynamically, depending on the time specified by the user. + +Thus, we have approached the need for arranging data input. diff --git a/skills/mql5/references/book/00-intro/0009-intro-data-input.md b/skills/mql5/references/book/00-intro/0009-intro-data-input.md new file mode 100644 index 0000000..a491d6e --- /dev/null +++ b/skills/mql5/references/book/00-intro/0009-intro-data-input.md @@ -0,0 +1,72 @@ +# Data input + +The basic way of data transfer into an MQL program is to use input parameters. They are similar to those of functions and just variables, from many aspects, particularly, in terms of description syntax and principles of their further use in the code. + +Moreover, an input parameter description has some essential differences: + +- It is placed in the text outside of all blocks (we have learned just the blocks constituting the body of functions yet, but we will learn about the other ones later) or, in other words, beyond any pairs of braces; +- It starts with the keyword input; and +- It is initialized with a default value. + +It is usually recommended to place input parameters at the start of the source code. + +For instance, to define an input parameter for entering the hour number in our script, the next string should be added immediately upon the triple of directives #property: + +``` +input int GreetingHour = 0; + +``` + +This record means several things. + +- First, there is the GreetingHour variable in the script now, which is available from any place of the source code, including from inside of any function. This definition is called a global-level definition, which is due to the execution of item 1 from the list above. +- Second, using the input keyword makes such a variable visible inside the program and in the user interface, in the MQL5 program properties dialog, which opens when it starts. Thus, when starting the program, a user sets the necessary value of parameters (in our case, one parameter GreetingHour), and they become the values of the corresponding variables during the execution of the program. + +Let's note again that the default value that we have specified in the code will be shown to the user in the dialog. However, the user will be able to change it. In this case, it is that new, manually entered value that will be included in the program (not the initialization value). + +The initial value of input parameters is affected by both the initialization in the code and the user's interactive choice in launching them, and the MQL5 program type, and the way it is launched. The matter is that different types of MQL5 programs have different life cycles after being launched on charts. Thus, upon a one-time placement in the chart, indicators and Expert Advisors are 'registered' in it forever, until the user removes them explicitly. Therefore, the terminal remembers the latest settings selected and uses them automatically, for example, upon the terminal restart. However, scripts are not saved in charts between the terminal sessions. Therefore, only the default value may be shown to us when we launch the script. + +Unfortunately, for some reason, the description of an input parameter does not guarantee calling the dialog of settings at the script start (for scripts as an independent MQL5 program type). For this to happen, it is necessary to add one more, script-specific directive #property into the code: + +``` +#property script_show_inputs + +``` + +As we will see further, this directive is not required for other types of MQL5 programs. + +We needed GreetingHour to transfer its value into the Greeting function. To do so, it is sufficient to insert it into the Greeting function call, instead of 0: + +``` +void OnStart() +{ +  Print(Greeting(GreetingHour), ", ", Symbol()); +} + +``` + +Considering the changes we have made to describe the input parameter, let's save the new script version in file GoodTime1.mq5. If we compile and start it, we will see the data entry dialog: + +![Dialog to enter the parameters of script GoodTime1.mq5](pics/goodtime1_en.png) + +Dialog to enter the parameters of script GoodTime1.mq5 + +For instance, if we edit the value GreetingHour to 10, then the script will display the following greeting: + +``` +GoodTime1 (EURUSD,H1)        Good afternoon, EURUSD + +``` + +This is a correct and expected result. + +Just for the fun of it, let's run the script again and enter 100. Instead of any meaningful response, we will get: + +``` +GoodTime1 (EURUSD,H1)        array out of range in 'GoodTime1.mq5' (19,18) + +``` + +We have just encountered a new phenomenon, i.e., runtime error. In this case, the terminal notifies that in position 18 of string 19, our script has tried to read the value of an array element having a non-existing index (beyond the array size). + +Since errors are a permanent and necessary companion of a programmer and we have to learn how to fix them, let's talk in some more details about them. diff --git a/skills/mql5/references/book/00-intro/0010-intro-errors-debug.md b/skills/mql5/references/book/00-intro/0010-intro-errors-debug.md new file mode 100644 index 0000000..9520cd4 --- /dev/null +++ b/skills/mql5/references/book/00-intro/0010-intro-errors-debug.md @@ -0,0 +1,98 @@ +# Error fixing and debugging + +Programming art relies on the ability to instruct the program what and how it must do and also to protect it against potentially doing something wrong. The latter one is unfortunately much more difficult to execute due to multiple not very obvious factors affecting the program behavior. Incorrect data, insufficient resources, somebody else's and one's own coding errors are just to name some of the problems. + +Nobody is insured against errors in coding programs. Errors may occur at different stages and are conveniently divided into: + +- Compilation errors returned by the compiler when identifying a source code that does not meet the required syntax (we have already learned about such errors above); it is easiest to fix them because the compiler searches for them; +- Program runtime errors returned by the terminal, if an incorrect condition occurs in the program, such as division by zero, computing the square root of a negative, or an attempt to refer to a non-existing element of the array, as in our case; they are more difficult to detect since they usually occur not at any values of input parameters, but only in specific conditions; +- Program designing errors that lead to its complete shutdown without any tips from the terminal, such as sticking at an infinite loop; such errors may turn out to be the most complex in terms of locating and reproducing them, while the reproducibility of a problem in the program is a necessary condition for fixing it afterward; and +- Hidden errors, where the program seems to work smoothly, but the result provided is not correct; it is easy to detect if 2*2 is not 4, while it is much more difficult to notice the discrepancies. + +But let's get back to the specific situation with our script. According to the error message provided to us by the MQL program runtime environment, the following statement is wrong: + +``` +return messages[hour / 8] + +``` + +In computing the index of an element from the array, depending on the value of the hour variable, a value may be obtained that goes beyond the array size of three. + +The debugger embedded in MetaEditor allows making sure that it really happens. All its commands are collected in the Debug menu. They provide many useful functions. Here we are going to only settle on two: Debut -> Start on Real Data (F5) and Debug -> Start on History Data (Ctrl+F5). You can read about the other ones in the MetaEditor Help. + +Both commands compile the program in a special manner — with the debugging information. Such a version of the program is not optimized as in standard compilation (more details on optimization, please see Documentation), while at the same time, it allows using the debugging information to 'look inside' the program during execution: See the states of variables and function call stacks. + +The difference between debugging on real data and on history data consists in starting the program on an online chart with the former one and on the tester chart in a visual mode with the latter one. To instruct the editor on what exactly chart and with which settings to use, i.e., symbol, timeframe, date range, etc., you should preliminarily open the dialog Settings -> Debug and fill out the required fields in it. Option Use specified settings must be enabled. If it is disabled, the first symbol from the Market Watch and timeframe H1 will be used in online debugging, while tester settings are used when debugging on history data. + +Please note that only indicators and Expert Advisors can be debugged in the tester. Only online debugging is available to scripts. + +Let's run our script using F5 and enter 100 in parameter GreetingHour to reproduce the above problem situation. The script will start executing, and the terminal will practically immediately display an error message and request for opening the debugger. + +``` +Critical error while running script 'GoodTime1 (EURUSD,H1)'. +Array out of range. +Continue in debugger? + +``` + +Having responded in the affirmative, we will get into MetaEditor where the current string is highlighted in the source code, in which the error has occurred (please give a notice of the green arrow in the left field). + +![MetaEditor in the debugging mode in case of an error](pics/me_debug_en.png) + +MetaEditor in the debugging mode in case of an error + +The current call stack is displayed in the lower left window part: All functions are listed in it (in bottom-up order), which had been called before the code execution stopped at the current string. In particular, in our script, the OnStart function was called (by the terminal itself), and the Greeting function was called from it (we called it from our code). An overview panel is in the lower right part of the window. Names of variables can be entered into it, or the entire expressions into the Expression column, and watch their values in the Values columns in the same string. + +For instance, we can use the Add command of the context menu or double-click with the mouse on the first free string to enter the expression "hour / 8" and make sure that it is equal to 12. + +Since debugging stopped resulting from an error, there is no sense to continue the program; therefore we can execute the Debug -> Stop command (Shift+F5). + +In more complex cases of a not so obvious problem source, the debugger allows the string-by-string monitoring of the sequence of executing the statements and the contents of variables. + +To solve the problem, it is necessary to ensure that, in the code, the element index always falls within the range of 0-2, i.e., complies with the array size. Strictly speaking, we should have written some additional statements checking the data entered for correctness (in our case, GreetingHour can only take a value within the range of 0-23), and then either display a tip or fix it automatically in case of violation of the conditions. + +Within this introductory project, we will not go beyond a simple correction: We will improve the expression that computes the element index so that its result always falls within the required range. For this purpose, let's learn about one more operator — the modulus operator that only works for integers. To denote this operation, we use symbol '%'. The result of the modulus operation is the remainder of the integer division of dividend by the divisor. For example: + +``` +11 % 5 = 1 + +``` + +Here, with the integer division of 11 by 5, we would obtain 2, which corresponds with the largest factor of 5 within 11, which is 10. The remainder between 11 and 10 is exactly 1. + +To fix the error in function Greeting, suffice to preliminarily perform the modulus division of hour by 24, which will ensure that the hour number will range within 0-23. Function Greeting will look as follows: + +``` +string Greeting(int hour) +{ +  string messages[3] = {"Good morning", "Good afternoon", "Good evening"}; +  return messages[hour % 24 / 8]; +} + +``` + +Although this correction will surely work well (we are going to check it in a minute), it does not concern another problem that is left beyond our focus. The matter is that the GreetingHour parameter is of the int type, i.e., it can take both positive and negative values. If we tried to enter -‌8, for instance, or a 'more negative' number, then we would get the same runtime error, i.e., going beyond the array; just, in this case, the index does not exceed the highest value (array size) but becomes smaller than the lowest one (particularly, -8 leads to referring to the -1st element, interestingly, the values from -7 to -1 being displayed onto the 0th element and do not cause any error). + +To fix this problem, we will replace the type of parameter GreetingHour with the unsigned integer: We will use uint instead of int (we will tell about all available types in part two, and here it is uint that we need). Guided by the limit for the non-negativity of values, built in at the compiler level for uint, MQL5 will independently ensure that neither the user (in the properties dialog) nor the program (in its computation) "goes negative." + +Let's save the new version of the script as GoodTime2, compile, and launch it. We enter the value of 100 for the GreetingHour parameter and make sure that, this time, the script is executed without any errors, while the greeting "Good morning" is printed in the terminal log. It is the expected (correct) behavior since we can use a calculator and check that the remainder of the modulus division of 100 by 24 gives 4, while the integer division of 4 by 8 is 0, which means morning, in our case. From the user's point of view, of course, this behavior can be considered as unexpected. However, entering 100 as the hour number was also an unexpected user action. The user probably thought that our program would go down. But this did not happen, and this is a good point. Of course, with real programs, the values entered must be validated and the user must be notified about bugs. + +As an additional measure of preventing from entering a wrong number, we will also use a special MQL5 feature to give a more detailed and friendly name to the input parameter. For this purpose, we will use a comment after the input parameter description in the same string. For example, like this: + +``` +input uint GreetingHour = 0; // Greeting Hour (0-23) + +``` + +Please note that we have written the words from the variable name separately in the comment (it is not an identifier in the code anymore, but a tip for the user in it). Moreover, we added the range of valid values in parentheses. When launching the script, the previous GreetingHour will appear in the dialog to enter the parameters as follows: + +``` +Greeting Hour (0-23) + +``` + +Now we can be sure that, if 100 is entered as the hour, it is not our fault. + +A careful reader may wonder why we have defined the Greeting function with the hour parameter and send GreetingHour into it if we could use the input parameter in it directly. Function, as a discrete logical fragment of a code, is formed for both dividing the program into visible and easy-to-understand parts and reusing them subsequently. Functions are usually called from several parts of the program or are part of a library that is connected to multiple different programs. Therefore, a properly written function must be independent of the external context and can be moved among programs. + +For instance, if we need to transfer our function Greeting into another script, it will stop being compiled, since there won't be the GreetingHour parameter in it. It is not quite correct to require adding it, because the other script can compute the time in another manner. In other words, when writing a function, we should do our best to avoid unnecessary external dependencies. Instead, we should declare the function parameters that can be filled out with the calling code. diff --git a/skills/mql5/references/book/00-intro/0011-intro-a-data-output.md b/skills/mql5/references/book/00-intro/0011-intro-a-data-output.md new file mode 100644 index 0000000..7aae02a --- /dev/null +++ b/skills/mql5/references/book/00-intro/0011-intro-a-data-output.md @@ -0,0 +1,33 @@ +# Data output + +In the case of our script, data are output by simply recording the greeting into the log using the Print function. Where necessary, MQL5 allows saving the results in files and databases, sending over the Internet, and displaying as graphical series (in indicators) or objects on charts. + +The simplest way to communicate some simple momentary information to the user without making him or her looking into the log (which is a service tool for monitoring the operation of programs and may be hidden from the screen) is provided by the MQL5 API function Comment. It can be used exactly as that of Print. However, its execution results in displaying the text not in the log, but on the current chart, in its upper left corner. + +For instance, having replaced Print with Comment in the text script, we will obtain such a function Greeting: + +``` +void OnStart() +{ +  Comment(Greeting(GreetingHour), ", ", Symbol()); +} + +``` + +Having launched the changed script in the terminal, we will see the following: + +![Displaying text information on the chart using the Comment function](pics/comment.png) + +Displaying text information on the chart using the Comment function + +If we need both display the text for the user and draw their attention to a change in the environment, related to the new information, it is better to use function Alert. It sends a notification into a separate terminal window that pops up over the main window, accompanying it with a sound alert. It is useful, for example, in case of a trade signal or non-routine events requiring the user's intervention. + +The syntax of Alert is identical to that of Print and Comment. + +The image below shows the result of the Alert function operation. + +![Displaying a notification using the Alert function](pics/alert-ru.png) + +Displaying a notification using the Alert function + +Script versions with functions Comment and Alert are not attached to this book for the reader to independently try and edit GoodTime2.mq5 and reproduce the screenshots provided herein. diff --git a/skills/mql5/references/book/00-intro/0012-intro-b-formatting.md b/skills/mql5/references/book/00-intro/0012-intro-b-formatting.md new file mode 100644 index 0000000..2ba2d8e --- /dev/null +++ b/skills/mql5/references/book/00-intro/0012-intro-b-formatting.md @@ -0,0 +1,69 @@ +# Formatting, indentation, and spaces + +MQL5 is among the so-called free-form languages, such as C-like and many other languages. This means that placing service symbols, such as brackets or operators, and keywords may be random, provided that syntactic rules are followed. The syntax only limits the mutual sequence of those symbols and words, while the indentation size at each string start or the number of spaces between the elements of the statement have no meaning for the compiler. In any place in the text, where a space needs to be inserted to separate language elements from each other, such as a variable type keyword and a variable identifier, a larger number of spaces can be used. Moreover, instead of spaces, it is allowed to use other symbols that denote empty space, such as tabulation and line breaks. + +If there is a separating symbol (we will learn more about them in Part 2) between some elements of the statement, such as a comma ',' between function parameters, then there is no need for using any spaces at all. + +Changes in formatting the source code do not modify the executable code. + +Basically, there are many non-free-form languages. In some of them, forming a code block, which is performed using brace matching in MQL5, is based on equal indents from the left edge. + +Due to free formatting, MQL5 allows programmers to use multiple different techniques to form the source code in order to improve its readability, visibility, and easier internal navigation. + +Let's consider some examples of how the source text of the Greeting function can be recorded from our script, without changing its intent. + +Here is the most 'packed' version without any excessive spaces or line breaks (a line break denoted here with the symbol '\' is only added to comply with the restrictions on publishing source codes in this book). + +``` +string Greeting(int hour){string messages[3]={"Good morning",\ +"Good afternoon","Good evening"};return messages[hour%24/8];} + +``` + +Here is the version, in which excessive spaces and line breaks are inserted. + +``` +string +Greeting ( int hour ) +  { +    string messages [ 3 ] +            = { +                "Good morning" , +                "Good afternoon" , +                "Good evening" +              } ; +       +    return messages [ hour % 24 / 8 ] ; +  } + +``` + +MetaEditor has a built-in code styler that allows automatically formatting the source code of the current file in compliance with one of the styles supported. A specific style can be selected in dialog Tools -> Settings -> Styler. A style is applied using Tools -> Styler command. + +You should keep in mind that your spacing freedom is limited. In particular, you may not insert spaces into identifiers, keywords, or numbers. Otherwise, the compiler won't be able to recognize them. For example, if we insert just one space between digits 2 and 4 in the number 24, the compiler will return a bunch of errors trying to compile the script. + +Here is a knowingly incorrectly modified string: + +``` +return messages[hour % 2 4 / 8]; + +``` + +Here is the error log: + +``` +'GoodTime2.mq5'        GoodTime2.mq5        1        1 +'4' - some operator expected        GoodTime2.mq5        19        28 +'[' - unbalanced left parenthesis        GoodTime2.mq5        19        18 +'8' - some operator expected        GoodTime2.mq5        19        32 +']' - semicolon expected        GoodTime2.mq5        19        33 +']' - unexpected token        GoodTime2.mq5        19        33 +5 errors, 0 warnings                6        1 + +``` + +Compiler messages may not always appear clear. It should be considered that, even upon the very first (in succession) error, there is a high probability that the internal representation of the program (as the compiler perceived it in 'mid-sentence') differs considerably from what the programmer has suggested. In particular, in this case, only the first and the second errors contain the key to understanding the problem, while all other ones are propagated. + +According to the first error, the compiler expected to find the symbol of an operation between 2 and 4 (as it perceives 2 and 4 as two different numbers and not as 24 separated by a space). Alternative logic consists in the fact that a closing square bracket is omitted here, and the compiler displayed the second error: "'[' - unbalanced left parenthesis." After that running through the expression gets completely shattered, due to which the subsequent number 8 and closing bracket ']' appear inappropriate to the compiler. But in fact, if we just delete the excessive space between 2 and 4, the situation will become normal. + +It is, of course, much easier to perform such an error analysis where we have intentionally added the issue. We do not always understand in practice how to remedy one situation or another. Even in the case above, supposing that you have received this broken code from another programmer and the array elements do not contain such trivial information, another correction option is easy to suspect: Either 2 or 4 must be left, because the author has probably desired to replace one number with another and not cleaned the 'footprints'. diff --git a/skills/mql5/references/book/00-intro/0013-intro-c-summing-up.md b/skills/mql5/references/book/00-intro/0013-intro-c-summing-up.md new file mode 100644 index 0000000..8ed73bd --- /dev/null +++ b/skills/mql5/references/book/00-intro/0013-intro-c-summing-up.md @@ -0,0 +1,9 @@ +# Mini summary + +In Part 1, we got familiar with the MetaEditor framework, created a script template using MQL Master, and gradually filled the script with code to solve a simple problem. For this purpose, we used some basic principles and syntactic structures of MQL5. Then we tried the debugger in practice, fixed some issues, and came to a stable program operation. + +Our script samples evolved as follows: + +![In the subsequent sections of this book, we will start to explore in detail these and many other features of MQL5, the technical aspects of programming, and its applications for trading.](pics/part1gog.png) + +In the subsequent sections of this book, we will start to explore in detail these and many other features of MQL5, the technical aspects of programming, and its applications for trading. diff --git a/skills/mql5/references/book/00-intro/pics/alert-ru.png b/skills/mql5/references/book/00-intro/pics/alert-ru.png new file mode 100644 index 0000000..88a830c Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/alert-ru.png differ diff --git a/skills/mql5/references/book/00-intro/pics/comment.png b/skills/mql5/references/book/00-intro/pics/comment.png new file mode 100644 index 0000000..ba8d244 Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/comment.png differ diff --git a/skills/mql5/references/book/00-intro/pics/goodtime1_en.png b/skills/mql5/references/book/00-intro/pics/goodtime1_en.png new file mode 100644 index 0000000..31254fe Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/goodtime1_en.png differ diff --git a/skills/mql5/references/book/00-intro/pics/me_compile_en.png b/skills/mql5/references/book/00-intro/pics/me_compile_en.png new file mode 100644 index 0000000..831365b Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/me_compile_en.png differ diff --git a/skills/mql5/references/book/00-intro/pics/me_debug_en.png b/skills/mql5/references/book/00-intro/pics/me_debug_en.png new file mode 100644 index 0000000..c87e14f Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/me_debug_en.png differ diff --git a/skills/mql5/references/book/00-intro/pics/me_edit_en.png b/skills/mql5/references/book/00-intro/pics/me_edit_en.png new file mode 100644 index 0000000..fab5e64 Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/me_edit_en.png differ diff --git a/skills/mql5/references/book/00-intro/pics/me_error_en.png b/skills/mql5/references/book/00-intro/pics/me_error_en.png new file mode 100644 index 0000000..ba12065 Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/me_error_en.png differ diff --git a/skills/mql5/references/book/00-intro/pics/mt_navex_en.png b/skills/mql5/references/book/00-intro/pics/mt_navex_en.png new file mode 100644 index 0000000..9dfa651 Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/mt_navex_en.png differ diff --git a/skills/mql5/references/book/00-intro/pics/part1gog.png b/skills/mql5/references/book/00-intro/pics/part1gog.png new file mode 100644 index 0000000..eeffaae Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/part1gog.png differ diff --git a/skills/mql5/references/book/00-intro/pics/wizard_script_name_params_en.png b/skills/mql5/references/book/00-intro/pics/wizard_script_name_params_en.png new file mode 100644 index 0000000..b849c37 Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/wizard_script_name_params_en.png differ diff --git a/skills/mql5/references/book/00-intro/pics/wizard_start_en.png b/skills/mql5/references/book/00-intro/pics/wizard_start_en.png new file mode 100644 index 0000000..e0a642d Binary files /dev/null and b/skills/mql5/references/book/00-intro/pics/wizard_start_en.png differ diff --git a/skills/mql5/references/book/0000-book.md b/skills/mql5/references/book/0000-book.md new file mode 100644 index 0000000..86c0239 --- /dev/null +++ b/skills/mql5/references/book/0000-book.md @@ -0,0 +1,23 @@ +Modern trading relies heavily on computer technology. Automation now extends beyond the boundaries of exchanges and brokerage offices, becoming accessible to everyday users through specialized software solutions. Among the pioneers in this field stands MetaTrader, which emerged in the early 2000s. The latest platform version, [MetaTrader 5](https://www.metatrader5.com/en), remains at the forefront, continuously evolving with innovative features and functionalities. + +A key element continuously refined within MetaTrader 5 is its built-in programming language MQL5. It enables traders to ascend to a whole new level of trading automation, commonly referred to as Algorithmic Trading. With MQL5, traders can transform their strategies into applications by writing their own indicators for analysis, scripts for executing operations, or Expert Advisor for complete trading automation. Being an automated trading system, an Expert Advisor can operate autonomously, tracking price changes and promptly alerting traders via email or SMS. + +The built-in programming language allows traders to implement virtually any trading concept, from simple strategies to complex algorithms based on neural networks. MQL5 seamlessly combines the features of domain-specific and universal programming languages. Over the years, the language has acquired valuable advancements, such as support for 3D graphics, parallel computations via OpenCL, Python integration, and SQLite database support. + +To unlock the full potential of MetaTrader 5, you must delve into programming. This book will help you master MQL5 and learn how to create your own trading applications. + +It is assumed that the reader is already familiar with MetaTrader 5. Another prerequisite is the understanding of the fundamental principles of terminal operation within a distributed information system that facilitates trading. The terminal [Help](https://www.metatrader5.com/en/terminal/help) provides detailed information on all available features. + +Furthermore, using MQL5 API, traders can access capabilities far beyond the MetaTrader 5 GUI. Master the programming language to implement complex scenarios, automating various terminal operation aspects and enhancing trading strategy efficiency. + +The book is divided into 7 parts, each focusing on different aspects of MQL5 programming. + +- [Part 1](/en/book/intro) introduces basic MQL5 programming principles and MetaEditor, the standard MQL5 framework. Users experienced in programming in other languages should note the features of the framework. +- [Part 2](/en/book/basis) explains the basic terms, such as types, instructions, operators, expressions, variables, code blocks, program structures. It describes how these terms are utilized in MQL5 procedural programming style. Those users who know MQL4 well can skip this part and start reading Part 3. +- [Part 3](/en/book/oop) deals with object oriented programming (OOP) in MQL5. Despite its similarity to other languages that support the OOP paradigm (especially to C++), MQL5 has certain specific features. To taste, MQL5 is sort of C±±. +- [Part 4](/en/book/common) describes common embedded functions which are applicable to in any program. +- [Part 5](/en/book/applications) covers the architectural features of MQL programs and their "majoring" in types to perform various trading tasks, such as technical analysis using indicators, chart management and marking the charts with imposing graphical objects onto them, and responses to interactive actions and events involving MQL programs. +- [Part 6](/en/book/automation) explains how to analyze trading environment and automate trading operations using robots. This part also presents the program interaction with tester in various modes, including strategy optimization. +- [Part 7](/en/book/advanced) contains information regarding the extended set of dedicated APIs facilitating the MQL5 integration with adjacent technologies, such as databases, network data exchange, OpenCL, Python, etc. + +Throughout the book, the material is presented in a balanced manner, combining common approaches, examples, and technical details. The reader is guided through transitioning from one concept to another, resembling a chicken-and-egg problem inherent in learning programming. To reinforce understanding, most MQL programs discussed in the book are available as source codes for practical exploration in MetaEditor/MetaTrader 5. diff --git a/skills/mql5/references/book/01-basis/0014-basis.md b/skills/mql5/references/book/01-basis/0014-basis.md new file mode 100644 index 0000000..2dc3a44 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0014-basis.md @@ -0,0 +1,52 @@ +# MQL5 programming fundamentals + +Like any other programming language, MQL5 is based on some fundamental concepts used to create more complex structures and, eventually, programs as a whole. In this Part, we are going to learn most of the concepts, such as data types, identifiers, variables, expressions, and operators, as well as the techniques to combine various statements in the code for building the desired program operation logic. + +The material assists our readers in progressing to the independent practical application of the procedural programming, This is one of the very first programming trends to solve various problems. In fact, it is the formation of a program from small steps (statements) to be executed in the required sequence for data processing. The text script shown in Part 1 of this book is an example of such a style. + +This section covers a broad spectrum of fundamental concepts and tools essential for successful MQL5 programming, including the following subsections: + +[Identifiers](/en/book/basis/identifiers): + +- Identifiers form the foundation of any program code. This subsection discusses the purpose and rules for naming identifiers in MQL5. + +[Built-in data types](/en/book/basis/builtin_types): + +- MQL5 includes a variety of built-in data types, each designed to store and process specific types of information. This section provides a comprehensive understanding of basic data types. + +[Variables](/en/book/basis/variables): + +Variables are used to store and manage data in a program. The "Variables" section teaches the basics of working with variables and considers how to declare, initializing, and assign values to them. + +[Arrays](/en/book/basis/arrays): + +- Arrays provide a structured way to store data. This section covers the basics of creating and using arrays in MQL5. + +[Expressions](/en/book/basis/expressions): + +- Expressions form the basis of calculations and program logic. From this subsection, you will learn how to construct and evaluate expressions in MQL5. + +[Type conversion](/en/book/basis/conversion): + +- Data type conversion is an integral part of programming. The "Type Conversion" section provides an understanding of the process related of converting data between different types in MQL5. + +[Statements:](/en/book/basis/statements) + +- Statements are commands that control program execution. In this section, we will look at various types of statements and their applications. + +[Functions](/en/book/basis/functions): + +- Functions allow for code structuring and reuse. This section dives into the basics of creating and calling functions in MQL5. + +[Preprocessor](/en/book/basis/preprocessor): + +- The MQL5 preprocessor processes the source code before compilation. The "Preprocessor" section describes the principles of using preprocessor directives and their impact on the code. + +Procedural programming principles will act as the basis for the subsequent learning of a more powerful paradigm, i.e., Object-Oriented Programming (OOP). It will be referred to in Part 3. + +``` +MQL5 Programming for Traders — Source Codes from the Book. Part 2 + +Examples from the book are also available in the public project \MQL5\Shared Projects\MQL5Book + +``` diff --git a/skills/mql5/references/book/01-basis/0015-basis-identifiers.md b/skills/mql5/references/book/01-basis/0015-basis-identifiers.md new file mode 100644 index 0000000..443f189 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0015-basis-identifiers.md @@ -0,0 +1,49 @@ +# Identifiers + +As we are going to see soon, programs are built of multiple elements that must be referred to by unique names to avoid confusion. These names are exactly what is called identifiers. + +Identifier is a word composed by certain rules: Only Latin characters, underscore characters ('_'), and digits may be used in it, and the first character may not be a digit. Letters can be small (lower-case) and capital (upper-letter). + +The maximum identifier length is 63 characters. The identifier may not coincide with any service words of MQL5, such as type names. You can find the full list of service words in the Help. Violating any of the identifier forming rules will cause a compilation error. + +Here are some correct identifiers: + +``` +i             // single character +abc           // lower-case letters +ABC           // upper-case letters +Abc           // mixed-case letters +_abc          // underscore at the beginning +_a_b_c_       // underscore anywhere +step1         // digit +_1step        // underscore and digit + +``` + +We have already seen in the script HelloChart how identifiers are used as names of variables and functions. + +It is recommended to provide identifiers with meaningful names, from which the purpose or content of the relevant element becomes clear. In some cases, single-character identifiers are used, which we will discuss in the section dealing with [loops](/en/book/basis/statements/statements_for). + +There are some common practices for composing identifiers. For instance, if we choose a name for a variable that stores the value of profit factor, the following options will be good: + +``` +ProfitFactor   // "camel" style, all words start with a capital letter +profitFactor   // "camel" style, all words but the first one start with a capital letter +profit_factor  // "snake" style, the underscore is put between all words + +``` + +In many programming languages, different styles are used to name different entities. For example, a practice may be followed, in which variable names only start with a lower-case letter, while class names (see [Part 3](/en/book/oop)) with upper-case letters. This helps the programmer analyze the source code when working in a team or if they return to their own code fragment after a long break. + +Along the above ones, there are other styles, some of which are used in special cases: + +``` +profitfactor   // "smooth" style, all letters are lower-case +PROFITFACTOR   // "smooth" style, all letters are upper-case +PROFIT_FACTOR  // "macro" style, all letters are upper-case with underscores between the words + +``` + +All capitals are sometimes used in the names of [constants](/en/book/basis/variables/const_variables). + +"Macro" style is conventionally used in the names of [preprocessor](/en/book/basis/preprocessor/preprocessor_define_overview) macro descriptions. diff --git a/skills/mql5/references/book/01-basis/0016-basis-builtin-types.md b/skills/mql5/references/book/01-basis/0016-basis-builtin-types.md new file mode 100644 index 0000000..e874998 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0016-basis-builtin-types.md @@ -0,0 +1,55 @@ +# Built-In Data Types + +The data type is a fundamental concept we comfortably use in our everyday life without even thinking of its existence. It is implied based on the meaning of the information we exchange and on the processing procedures admissible for it. For example, controlling our household assets, we add and deduct numbers representing our revenues and expenses. Here, the 'number' describes a type, for which we realize fully its possible values and arithmetic operations on them. In the trading context, there is a similar value, the current account balance, in MetaTrader 5; therefore, MQL5 provides a mechanism to create and manipulate numbers. + +Unlike numbers, text information, such as the name of a trading instrument, conforms to other rules. Here we can build a word of letters or a sentence of words, but it is impossible to compute the progressive total or arithmetic mean of several lines. Thus, 'line' or 'string' is another data type, not a numeric one. + +Along with the purpose and a typical set of operations that are meaningful for each type, there is another important thing that differs types from each other. It's their size. For instance, the week number cannot exceed 52 within a year, while the number of seconds that have elapsed from the beginning of the year represents an astronomical shape. Therefore, to efficiently store and process such different values in the computer memory, differently sized segments can be singled out. This leads us to understand that, in fact, the generalizing concept of a 'number' may hide different types. + +MQL5 allows the used of some number types differing both in the sizes of memory cells allocated for them and in some additional features. In particular, some numbers may take negative values, such as floating profit in pips, while the other ones may not, such as account numbers. Moreover, some values cannot have a fractional part and therefore, it is more cost-efficient to represent them with a stricter type of 'integers', as opposed to those of random 'numbers with a decimal point'. For instance, an account balance or the price of a trading instrument generally have values with a decimal point. At the same time, the number of orders in history or, again, the account number is always an integer. + +MQL5 supports a set of universal types similar to those available in the vast majority of programming languages. The set includes integer types (different sizes), two types of real numbers (with a decimal point) of different precision, strings, and single characters, as well as the logical type that only has two possible values: true and false. Moreover, MQL5 provides its own, specific types operating with time and color. + +For the sake of completeness, let's note that MQL5 allows expanding the set of types, declaring applied types in the code, i.e., structures, classes, and other entities typical of OOP; but we are going to consider them later. + +Since the size of the cell where the value is stored is an important type attribute, let's touch on memory methodology. + +The smallest unit of computer memory is a byte. In other words, a byte is the smallest size of a cell that a program can allocate for a separate value. A byte consists of 8 smaller 'particles', bits, each being able to be in two states: Enabled (1) or disabled (0). All modern computers use such bits at the lower level because such a binary representation of information is convenient to be embodied in hardware(in random-access memory, in processors, or while transferring the data by network cables or via WiFi). + +Processing the values of different types is ensured due to the different interpretations of the bit states in memory cells. The compiler deals with this. Programmers usually do not go as low as bits; however, the language provides tools for that (see [Bitwise operations](/en/book/basis/expressions/operators_bitwise)). + +There are special reserved words in MQL5 to describe data types. We have already known some of them, such as void, int, and string, from Part 1. A complete list of types is given below, each with a quick reference and size in bytes. + +By their purpose, they can be conditionally divided into numeric and character-coded data (marked in the relevant columns), as well as other, specialized types, such as strings, logical (or boolean) types, date/time, and color. Type void stands apart and indicates there is no value at all. In addition to scalar types, MQL5 provides object types for operations with complex numbers, matrices, and vectors: complex, vector, and matrix. These types are used to solve various problems in linear algebra, mathematical modeling, machine learning, and other areas. We will study them in detail in Part 4 of the book. + +| Type | Size + (bytes) | Number | Character | Note | +| --- | --- | --- | --- | --- | +| char | 1 | + | + | Single-byte character or a signed integer | +| uchar | 1 | + | + | Single-byte character or an unsigned integer | +| short | 2 | + | + | Two-byte character or a signed integer | +| ushort | 2 | + | + | Two-byte character or an unsigned integer | +| int | 4 | + | | Signed integer | +| uint | 4 | + | | Unsigned integer | +| long | 8 | + | | Signed integer | +| ulong | 8 | + | | Unsigned integer | +| float | 4 | + | | Signed floating-point number | +| double | 8 | + | | Signed floating-point number | +| enum | 4 | (int) | | Enumeration | +| datetime | 8 | (ulong) | | Date and time | +| color | 4 | (uint) | | Color | +| bool | 1 | (uchar) | | Logical | +| string | 10+ + variable | | | String | +| void | 0 | | | Void | +| complex | 16 | + | | Structure with two double-type fields | +| vector | vector length x type size | + | | One-dimensional array of real or complex type | +| matrix | rows x columns x type size | + | | Two-dimensional array of real or complex type | + +Depending on its size, different value ranges may be stored in the numeric type. Along with the above, the range may considerably vary for the integers and floating-point numbers of the same size, because different internal representations are used for them. All these cobwebs will be considered in the sections dealing with specific types. + +A programmer is free to choose a numeric type based on the anticipated values, efficiency considerations, or for reasons of economy. Particularly, the smaller type size allows fitting more values of this type in memory, while integers are processed faster than floating-point numbers. + +Please note that numeric and character-coded types are partly crossed. This happens because a character is stored in memory as an integer, i.e., a code in the relevant table of characters: ANSI for single-byte chars or Unicode for two-byte ones. ANSI is a standard named after an institute (American National Standards Institute), while Unicode, you guessed it, means Universal Code (Character Set). Unicode characters are used in MQL5 to make strings (type string). Single-byte characters are usually required in integrating the programs with external data sources, such as those from the Internet. + +As mentioned above, numeric types can be divided into integers and floating-point numbers. Let's consider them in more detail. diff --git a/skills/mql5/references/book/01-basis/0017-basis-builtin-types-integer-numbers.md b/skills/mql5/references/book/01-basis/0017-basis-builtin-types-integer-numbers.md new file mode 100644 index 0000000..a06f0bf --- /dev/null +++ b/skills/mql5/references/book/01-basis/0017-basis-builtin-types-integer-numbers.md @@ -0,0 +1,97 @@ +# Integers + +Integer types are intended for storing numbers without decimal points. They should be chosen if the applied sense of the value excludes fractions. For example, the numbers of bars on a chart or of open positions are always integers. + +MQL5 allows choosing integer types sized 1-8 bytes using keywords char, short, int, and long, respectively. They all are the signed types, i.e., they can contain both positive and negative values. If necessary, integer types having the same sizes can be declared unsigned (their names starting with 'u' for 'unsigned'): uchar, ushort, uint, and ulong. + +Based on the type size and being signed/unsigned, the following table shows the ranges of potential values. + +| Type | min | max | +| --- | --- | --- | +| char | -128 | 127 | +| uchar | 0 | 255 | +| short | -32768 | 32767 | +| ushort | 0 | 65535 | +| int | -2147483648 | 2147483647 | +| uint | 0 | 4294967295 | +| long | -9223372036854775808 | 9223372036854775807 | +| ulong | 0 | 18446744073709551615 | + +There is no need to memorize the above limiting values for each integer. There are many predefined named constants in MQL5, which can be used in a code instead of 'magic' numbers, including the lowest/highest integers. This technology is considered in a section dealing with the [preprocessor](/en/book/basis/preprocessor/preprocessor_define_simple). Here, we just list the relevant named constants: CHAR_MIN, CHAR_MAX, UCHAR_MAX, SHORT_MIN, SHORT_MAX,USHORT_MAX, INT_MIN, INT_MAX, UINT_MAX, LONG_MIN, LONG_MAX, and ULONG_MAX. + +Let's explain how these values are obtained. This requires returning to bits and bytes. + +The number of all possible combinations of different states of 8 bits, enabled and disabled, within one byte, is 256. This produces the range of values 0-255 that can be stored in a byte. However, interpreting them depends on the type, for which this byte is allocated. Different interpretations are ensured by the compiler, according to the programmer's statements. + +The low-order (rightmost) bit in a byte means 1, the second 2, the third 4, and so on through the high-order bit that means 128. It's plain to see that these numbers are equal to two raised to a power equaling the bit number (numbering starts from 0). This is the effect of using the binary system. + +| Bits | high-order | low-order | +| --- | --- | --- | +| Number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +| Value | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | + +Where all bits are set, this produces the sum of all powers of two, i.e., 255 is the highest value for a byte. If all bits are reset, we get zero. If a low-order bit is enabled, the number is odd. + +In coding signed numbers, the high-order bit is used to mark negative values. Therefore, for a single-byte integer within the positive range, 127 becomes the highest value. For negative values, there are 128 possible combinations, i.e., the lowest value is -128. Where all bits in a byte are set, it is interpreted as -1. If the lower-order bit is reset in such a number, we will get -2, etc. If only the higher-order bit (sign) is set and all other bits are reset, we get -128. + +This coding that may seem to be irrational is called "additional." It allows you to unify computations of signed and unsigned numbers at the hardware level. Moreover, it allows you not to lose one value, which would happen if the positive and negative regions were coded identically: Then we would have got two values for zero, i.e., a positive 0 and a negative 0. What is more, this would bring ambiguity. + +Numbers with more bytes, i.e., 2, 4, or 8, have a similar consecutive numbering of bits and the progression of their respective values. In all cases, a criterion for the number negativity is the set high-order bit of the high-order byte. + +Thus, we can use a byte to store an unsigned integer (uchar, i.e., unsigned character abbreviated) within the range of 0-255. We can also write a signed integer into the byte (for which purpose we will describe its type as char). In this case, the compiler will divide the available amount of combinations of 256 equally between positive and negative values, having displayed it onto the region from -128 through 127 (the 256th value is zero). It's plain to see that values 0-127 will be coded equally at the bit level for signed and unsigned bytes. However, large absolute values, starting from 128, will turn into negative ones (according to the scheme described in the insertion above). This "transformation" only takes place at the moment of reading or performing any operations with the value stored, with the identical internal data representation (state of bits). + +We will consider this matter in more detail in the section dealing with [typecasting](/en/book/basis/conversion). + +In a similar manner as with single-byte integers, it is easy to calculate that the number of bit combinations is 65536 for 2 bytes. Hence, the ranges are formed for the signed and unsigned two-byte integer, short and ushort. Other types allow storing even larger values due to increasing their byte sizes. + +Please note that using an unsigned type with the same size allows doubling the highest positive value. This may be necessary for storing potentially very large quantities, for which no negative values may appear. For example, the order number in MetaTrader 5 is a value of the ulong type. + +We have already encountered the integer description samples in [Part 1](/en/book/intro). In particular, input parameter GreetingHour of type uint was defined there: + +``` +input uint GreetingHour = 0; + +``` + +Except for the additional keyword, input, that makes the variable visible in the list of parameters of an MQL program, other components, i.e., type, name, and optional initialization after the '=' sign, are intrinsic to all variables. + +Variable description syntax will be considered in detail in the [Variables](/en/book/basis/variables) section. So far, please note the method of recording the constants of integer type. In describing a variable, constants can be specified as a default value (in the example above, it is 0). Moreover, constants can be used in [expressions](/en/book/basis/expressions), for instance, in a formula event. + +It should be reminded that constants of any type, inserted in the source code, are named literals (textually: "word-for-word"). Their name derives from the fact that they are introduced into the program "as is" and used immediately at the point of description. Literals, unlike many other elements of the language, particularly variables, have no names and cannot be referred to from other points of the program. + +For negative numbers, it is required to provide the minus sign '-' before the number; however, the plus sign '+' can be omitted for positive numbers, i.e., forms +100 and just 100 are identical. + +It should be noted that numeric values are usually recorded in the source code within our habitual decimal notation. However, MQL5 allows using the other one, i.e., hexadecimal. It is convenient for processing bit-level information (see [Bitwise operations](/en/book/basis/expressions/operators_bitwise)). + +Numbers from 0 through 9 are permitted in all digit order numbers in decimal constants, while for hexadecimal ones, along with digits, Latin symbols from A through F or from a through f (that is, case does not matter) are used additionally. "Hexadecimal digit" A corresponds with number 10 of decimal notation, B — 11, C — 12, etc., up through F equal to 15. + +A distinctive feature of a hexadecimal constant is the fact that it begins with prefix 0x or 0X, followed by the significant digit orders of the number. For instance, number 1 is recorded as 0x1 in the hexadecimal system, while 16 as 0x10 (an additional higher order digit is required because 16 is greater than 15, that is, 0xF). Decimal 255 turns into 0xFF. + +Let's give some more examples illustrating various situations of using integer types in describing variables (attached in script MQL5/Scripts/MQL5Book/p2/TypeInt.mq5): + +``` +void OnStart() +{ +  int x = -10;          // ok, signed integer x = -10 +  uint y = -1;          // ok, but unsigned integer y = 4294967295 +  int z = 1.23;         // warning: truncation of constant value, z = 1 +  short h = 0x1000;     // ok, h = 4096 in decimal +  long p = 10000000000; // ok +  int w = 10000000000;  // warning, truncation..., w = 1410065408 +} + +``` + +Variable x is initialized correctly by the permitted negative value, -10. + +Variable y is unsigned. Therefore, an attempt to record a negative value in it leads to an interesting effect. Number -1 has a representation in bits, which is interpreted by the program in accordance with the unsigned type, uint. Therefore, number 4294967295 is obtained (it is actually equal to UINT_MAX). + +Variable z is assigned with the floating-point number 1.23 (they will be considered in the next section), and the compiler warns about the truncation of the fractional part. As a result, integer 1 gets into the variable. + +Variable h is successfully initialized by a constant in the hexadecimal form (0x1000 = 4096). + +The large value 10000000000 is recorded in variables p and w, the former of which is of a long integer type (long) and processed successfully, while the latter one of the normal type (int) and, therefore, calls for the compiler warning. Since the constant exceeds the maximum value for int, compiler truncates the excessive higher order digits (bits) and, in fact, 1410065408 gets into w. + +This behavior is one of the potential negative developments of type conversions that may or not may be implied by the programmer. In the latter case, it is fraught with a potential error. Clearly, in this particular example, wrong values were selected intentionally to demonstrate warnings. It is not always that obvious in a real program, which values the program is attempting to save in the integer variable. Therefore, you should look into the compiler warnings very carefully and try to make away with them, having changed the type or explicitly specified the required typecast. This will be considered in the section dealing with [Typecasting](/en/book/basis/conversion). + +For integer types, arithmetic, bitwise, and other types of operations are defined (see chapter [Expressions](/en/book/basis/expressions)). diff --git a/skills/mql5/references/book/01-basis/0018-basis-builtin-types-float-numbers.md b/skills/mql5/references/book/01-basis/0018-basis-builtin-types-float-numbers.md new file mode 100644 index 0000000..e80af87 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0018-basis-builtin-types-float-numbers.md @@ -0,0 +1,97 @@ +# Floating-point numbers + +We use numbers with a decimal point, or real numbers, in everyday life just as often as integers. The name 'real' itself indicates that using such numbers, you can express something tangible from the real world, such as weight, length, body temperature, i.e., everything that can be measured by a non-integer amount of units, but with "a little more." + +We often use real numbers in trading, too. For instance, they are used to express symbol prices or volumes in trading orders (normally permitting the fractional parts of a full-sized lot). + +There are 2 real types provided in MQL5: float for normal accuracy and double for double accuracy. + +In the source code, the constant values of types float and double are usually recorded as an integer and a fractional part (each being a sequence of digits), separated by the character '.', such as 1.23 or -789.01. There can be no integer or fraction (but not both at a time), but the point is mandatory. For instance, .123 means 0.123, while 123. means 123.0. Simply 123 will create a constant of integer type. + +However, there is another form of recording real constants, the exponential one. In it, the integer and fractional part are followed by 'E' or 'e' (case does not matter) and an integer representing the power, to which 10 should be raised to obtain an additional factor. For instance, the following representations display the same number, 0.57, in exponential form: + +``` + .0057e2 +0.057e1 +.057e1 +57e-2 + +``` + +When recording real constants, the latter ones are defined by default as type double (they consume 8 bytes). To set type float, suffix 'F' (or 'f') should be added to the constant on the right. + +Types float and double differ by their sizes, ranges of values, and number representation accuracy. All this is shown in the table below. + +| Type | Size (bytes) | Minimum | Maximum | Accuracy (digit orders) | +| --- | --- | --- | --- | --- | +| float | 4 | ±1.18 * 10 -38 | ±3.4 * 10 38 | 6-9, usually 7 | +| double | 8 | ±2.23 * 10 -308 | ±1.80 * 10 308 | 15-18, usually 16 | + +Range of values is shown for them in absolute terms: Minimum and maximum determine the amplitude of permitted values in both positive and negative regions. Similar to integer types, there are embedded named constants for these limiting values: FLT_MIN, FLT_MAX, DBL_MIN, DBL_MAX. + +Please note that real numbers are always signed, that is, there are no unsigned analogs for them. + +Accuracy shall mean the quantity of significant digits (decimal digits) the real number of the relevant type is able to store undistorted. + +Indeed, the numbers of real types are not as accurate as those of integer types. This is the price to be paid for their universality and a much wider range of potential values. For instance, if an unsigned 4-byte integer (uint) has the highest value of 4294967295, i.e., about 4 million, or 4.29*109, then the 4-byte real one (float) has 3.4 * 1038, which is by 29 orders of magnitude higher. For 8-byte types, the difference is even more perceptible: ulong can house 18446744073709551615 (18.44*1018, or ~18 quintillion), while double can house 1.80 * 10308, that is, by 289 orders of magnitude more. Insertion provides more detail regarding accuracy. + +Mantissa and Exponent + +  + +The internal representation of real numbers in memory (in the bytes allocated for them) is quite tricky. The higher-order bit is used as a marker of the negative sign (we have also seen that in integer types). All other bits are divided into two groups. The larger one contains the mantissa of the number, i.e., significant digits (we mean binary digits, i.e., bits). The smaller one stores the power (exponent), to which 10 must be raised to obtain the stored number upon multiplying it by the mantissa. Particularly, for type float mantissa is sized 24 bits (FLT_MANT_DIG), while for double it is 53 (DBL_MANT_DIG). In terms of conventional decimal places (digits), we will get the same accuracy that has been shown in the table above: 6 (FLT_DIG) is the lowest quantity of significant digits for float, while 15 (DBL_DIG) is that for double. However, depending on the particular number, it can have "lucky" combinations of bits, corresponding to a greater quantity of decimal digits. Sizes of the parameters are 8 and 11 bits for float and double, respectively. + +  + +Due to the exponent, real numbers get a much larger range of values. At the same time, with the increase in the exponent, the "specific weight" of the low-order digit of mantissa increases, too. This means that two neighboring real numbers that can be represented in the computer memory are substantially different. For instance, for number 1.0 the "specific weight" of the low-order bit is 1.192092896e—07 (FLT_EPSILON) in case of float and 2.2204460492503131e-016 (DBL_EPSILON) in case of double. In other words, 1.0 is indistinguishable from any number near it if such a number is below 1.192092896e—07. This may seem not very important or "not a big deal," but this uncertainty region gets larger for larger numbers. If you store in float a number about 1 billion (1*109), the last 2 digits will stop being safely stored or restored from memory (see the code sample below). However, basically, the problem is not the absolute value of a number, but the maximum quantity of digits in it, which should be recalled without losses. Equally "well," we can try to fit a number represented as 1234.56789 (which is structurally much like the price of a financial instrument) in float; and its two last digits will "float" due to the lack of accuracy in their internal representation. + +  + +For double, a similar situation will start showing for much greater numbers (or for a much greater quantity of significant digits), but it is still possible and often happens in practice. You should consider this when operating very large or very small real numbers and write your programs with additional checks for potential loss of accuracy. In particular, you should compare a real number with zero in a special manner. We will deal with it in the section on [comparison operators](/en/book/basis/expressions/operators_relational). + +  + +It may seem to a careful reader that the sizes of mantissa and exponent above are specified wrongly. Let's explain that exemplified by float. It is stored in the memory cell sized 4 bytes, that is, consumes 32 bits. At the same time, the sizes of mantissa (24) and exponent (8) sum to 32 already. Then where is the signed bit? The matter is that IT professionals arranged to store mantissa in the 'normalized' form. It will be easier to understand what it is if we consider the exponential form of recording a normal decimal number first. Let's say number 123.0 could be represented as 1.23E2, 12.3E1, or 0.123E3. A designation is considered to be the normalized form, where only one significant digit (i.e., not zero) is placed before the point. For this number, it is 1.23E2. By definition, digits from 1 through 9 are considered significant digits in decimal notation. Now we are smoothly going to the binary notation. There is only one significant digit in it, 1. It appears that the normalized form in binary notation always starts with 1, and it can be omitted (not to spend memory on it). In this manner, one bit can be saved in the mantissa. In fact, it contains 23 bits (one more higher-order unity is implicit and added automatically when reconstructing the number and retrieving it from memory). Reducing mantissa by 1 bit makes room for the signed bit. + +Predominantly, where the floating-point type should be used, we choose double as a more accurate one. Type float is only used to save memory, such as when working with very large data arrays. + +Some examples of using the constants of real types are shown in script MQL5/Scripts/MQL5Book/p2/TypeFloat.mq5. + +``` +void OnStart() +{ +  double a0 = 123;      // ok, a0 = 123.0 +  double a1 = 123.0;    // ok, a1 = 123.0 +  double a2 = 0.123E3;  // ok, a2 = 123.0 +  double a3 = 12300E-2; // ok, a3 = 123.0 +  double b = -.75;      // ok, b = -0.75 +  double q = LONG_MAX;  // warning: truncation, q = 9.223372036854776e+18 +                        //               LONG_MAX = 9223372036854775807 +  double d = 9007199254740992; // ok, maximal stable long in double +  double z = 0.12345678901234567890123456789; // ok, but truncated +                           // to 16 digits: z = 0.1234567890123457 +  double y1 = 1234.56789;  // ok, y1 = 1234.56789 +  double y2 = 1234.56789f; // accuracy loss, y2 = 1234.56787109375 +  float m = 1000000000.0;  // ok, stored as is +  float n =  999999975.0;  // warning: truncation, n = 1000000000.0 +} + +``` + +Variables a0, a1, a2, and a3 contain the same numbers (123.0) written in different methods. + +In the constant for variable b, the insignificant zero is omitted before the point. Moreover, here is the demonstration of recording a negative number using the minus sign, '-'. + +An attempt is made to store the greatest integer in variable q. At this place, the compiler gives a warning, because double cannot represent LONG_MAX accurately: Instead of 9223372036854775807, there will be 9223372036854776000. It obviously demonstrates that, even though the ranges of the double values exceed those of integers vastly, it is achieved due to losing the low-order digits. + +As a comparison, the maximum integer that the double type is able to store without any distortions is given as the value of variable d. In the sequence of integers, it will be followed by sporadic skips, if we use double for them. + +Variable z reminds us again about the limitation on the maximum quantity of significant digits (16) – a longer constant will be truncated. + +Variables y1 and y2, in which the same number is recorded in different formats (double and float), allow seeing the loss of accuracy due to the transition to float. + +In fact, variables m and n will be equal, because 999999975.0 is roughly stored in the internal representation and turns into 1000000000.0. + +Numeric types are often used to calculate using formulas; a wide set of operations is defined for them (see [Expressions](/en/book/basis/expressions)). + +Computations can sometimes lead to incorrect results, that is, they cannot be represented as a number. For example, the root of a negative number or the logarithm of zero cannot be defined. In such cases, real types can store a special value named NaN (Not A Number). In fact, there are several different types of such values that allow, for instance, telling the difference between plus infinity and minus infinity. MQL5 provides a special function, MathIsValidNumber, that checks whether the double value is a number or one of NaN values. diff --git a/skills/mql5/references/book/01-basis/0019-basis-builtin-types-characters.md b/skills/mql5/references/book/01-basis/0019-basis-builtin-types-characters.md new file mode 100644 index 0000000..a82f9ee --- /dev/null +++ b/skills/mql5/references/book/01-basis/0019-basis-builtin-types-characters.md @@ -0,0 +1,47 @@ +# Character types + +Character data types are intended for storing particular characters (letters), of which strings are formed (see [Strings](/en/book/basis/builtin_types/strings)). MQL5 has 4 character types: Two sized 1 byte (char, uchar) and two sized 2 bytes (short, ushort). Types prefixed with 'u' are unsigned. + +In fact, character types are integer ones, since they store an integer code of a character from the relevant table: For char, it is the table of ASCII characters (codes 0-127); for uchar, it is extended ASCII (codes 0-255); and for short/ushort, it is the Unicode table (up to 65535 characters in the unsigned version). If it is of any interest to you, ASCII is the abbreviated American Standard Code for Information Interchange. + +For MQL5 strings, 2-byte chars ushort are used. 1-byte uchar types are normally used to integrate with external programs when transferring the [arrays](/en/book/basis/arrays) of random data that are packed and unpacked in other types according to applied protocols, such as for connecting to a crypto platform. + +Constants of characters are recorded as letters enclosed in single quotes. However, you can also use the integer notation (see [Integers](/en/book/basis/builtin_types/integer_numbers)) considered above. At the same time, the integer must be within the range of values for 1- or 2-byte format. + +Additionally, we can use the notation of escape sequences. They use a backslash ('\') as the first character followed by one of the predefined control characters and/or a numerical code. MQL5 supports the following escape sequences: + +- \n — new line +- \r — carriage return +- \t — tabulation +- \\ — backslash +- \" — double quote +- \' — single quote +- \X or \x — prefix to subsequently specify a numerical code in hexadecimal format +- \0 — prefix to subsequently specify a numerical code in octal format + +Basic methods of using the constants of character types are given in script MQL5/Scripts/MQL5Book/p2/TypeChar.mq5. + +``` +void OnStart() +{ +  char a1 = 'a';  // ok, a1 = 97, English letter 'a' code +  char a2 = 97;   // ok, a2 = 'a' as well +  char b = '£';   // warning: truncation of constant value, b = -93 +  uchar c = '£';  // ok, c = 163, pound symbol code +  short d = '£';  // ok +  short z = '\0';    // ok, 0 +  short t = '\t';    // ok, 9 +  short s1 = '\x5c'; // ok, backslash code 92 +  short s2 = '\\';   // ok, backslash as is, code 92 as well +  short s3 = '\0134';// ok, backslash code in octal form +} + +``` + +Variables a1 and a2 get the value of character 'a' (English letter) in two different ways. + +There is an attempt to record '£' in variable b, but its code 163 is beyond the range char (127); therefore it is "transformed" into the signed -93 (compiler gives a warning). The variables of types uchar (c) and short (d) that follow it perceive this code as normal. + +Other variables are initialized using escape sequences. + +Characters can be processed with the same operations as integers (see [Expressions](/en/book/basis/expressions)). diff --git a/skills/mql5/references/book/01-basis/0020-basis-builtin-types-strings.md b/skills/mql5/references/book/01-basis/0020-basis-builtin-types-strings.md new file mode 100644 index 0000000..0e8346e --- /dev/null +++ b/skills/mql5/references/book/01-basis/0020-basis-builtin-types-strings.md @@ -0,0 +1,49 @@ +# String type + +String type is intended for storing text-based information and is marked by keyword string. String is a sequence of the ushort characters and supports the complete Unicode range, including multiple national scripts. For instance, names of financial instruments and comments in trading orders are strings. + +By reason of the specific nature of strings, their size is a variable value that is equal to the doubled length of the text (quantity of characters multiplied by the "width" of a character, i.e., 2 bytes) plus one more character. This additional character is intended for the 'terminating zero' (a char coded as 0) that denotes the end of the line. Moreover, MQL5 uses some space to store service information, i.e., a reference to the place in memory where the string starts. + +Unlike C++, no address of a string or any other variable can be obtained in MQL5. Direct memory access is prohibited in MQL5. + +A string literal is recorded in the source code as a sequence of characters embedded in double-quotes. For example: "EURUSD" or "$". We should distinguish between strings consisting of one character, like "$", and the same single characters, like '$'. These are different data types. + +An empty string appears as "". Considering the implicit terminating zero, it consumes 2 bytes, apart from service information. + +Should it be necessary to use the double quote character inside the string, it must be preceded by the backslash character, transforming into a control sequence, such as "Press \"OK\"". + +String initialization examples are given in script MQL5/Scripts/MQL5Book/p2/TypeString.mq5. + +``` +void OnStart() +{ +   string h = "Hello";          // Hello +   string b = "Press \"OK\"";   // Press "OK" +   string z = "";               // +   string t = "New\nLine";      // New +                                // Line +   string n = "123";            // 123, text (not an integer value) +   string m = "very long message " +              "can be presented "  +              "by parts"; +   // equivalent: +   // string m = "very long message can be presented by parts";  +} + +``` + +The string "Hello" is placed in variable h. + +Text containing double quotes is written in variable b. + +Variable z is initialized by an empty string. This is basically equivalent to describing z without initialization, but there are some finer points here. Further, as the text goes, in the section of [Initialization of variables](/en/book/basis/variables/initialization), we will get to know that uninitialized strings get a special value, NULL, unlike "", for which, as previously stated, the memory is allocated for the terminating zero. This difference affects the execution of string [comparison operators](/en/book/basis/expressions/operators_relational) and some others. As the story unfolds, we will touch upon all such aspects. + +Variable t will get a text that, when printed in the log using the Print function or displayed by other methods, will be divided into 2 strings. + +String "123" recorded in variable n is not a number, although it looks like that. There are some functions in MQL5 to convert text into numbers and back (see section [Data transformation](/en/book/common/conversions/conversions_numbers)). Moreover, there is a separate set of functions for [working with strings](/en/book/common/strings). + +For convenience, long literals can be written in several strings, as for variable m. The general rule is as follows: All literals up to the semicolon that marks the end of the variable description are merged by the compiler. In such formatting, the key is not to forget to add an intervening space inside each fragment of the string, if necessary (for instance, to separate the words in the message as in the example above). + +For strings, the summation (concatenation) operation is defined, denoted with the character '+'. We will discuss it in the chapter dealing with expressions (see [Arithmetic operations](/en/book/basis/expressions/operators_arithmetic)). + +String characters can be read separately, referring to them as array elements (see [Use of arrays](/en/book/basis/arrays/arrays_usage)): If s is a string, then s[i] is the code of the ith character in it, type ushort. diff --git a/skills/mql5/references/book/01-basis/0021-basis-builtin-types-booleans.md b/skills/mql5/references/book/01-basis/0021-basis-builtin-types-booleans.md new file mode 100644 index 0000000..15bb096 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0021-basis-builtin-types-booleans.md @@ -0,0 +1,24 @@ +# Logic (Boolean) Type + +Logic type is intended for storing features that only have 2 possible states: "enabled"/"disabled". Their interface analogs are options in setup dialogs of many programs, including MetaTrader 5: Each flag may be either enabled or disabled. Checking the states of such features allows branching the logic of the program execution, thus the type name. + +Logic type is defined in MQL5 under the bool keyword and consumes 1 byte of memory. For this type, two constants are reserved: true and false. Moreover, situations are permissible (and programmers often make use of it), in which bool is the result of computations with integers and real numbers, value 0 being interpreted as false, and any others as true. + +Back-interpretation of the bool type value as a number is supported, as well: true is considered as 1 and false as 0. + +Examples of logic type variables are given in file MQL5/Scripts/MQL5Book/p2/TypeBool.mq5. + +``` +void OnStart() +{ +  bool t = true;          // true +  bool f = false;         // false +  bool x = 100;           // x = true +  bool y = 0;             // y = false +  int i = true;           // i = 1 +  int j = false;          // j = 0 +} + +``` + +For logic type, a set of special logic operations is provided (see [Logical (Boolean) Operations](/en/book/basis/expressions/operators_logical) and [Comparison Operations](/en/book/basis/expressions/operators_relational)). diff --git a/skills/mql5/references/book/01-basis/0022-basis-builtin-types-datetime.md b/skills/mql5/references/book/01-basis/0022-basis-builtin-types-datetime.md new file mode 100644 index 0000000..393114f --- /dev/null +++ b/skills/mql5/references/book/01-basis/0022-basis-builtin-types-datetime.md @@ -0,0 +1,43 @@ +# Date and time + +MQL5 provides a special type for storing time data datetime. As follows from its name, the values of datetime include both the date and time. However, where necessary, they can contain only the date or only the time of day. + +Values of this type can be used in programs to monitor events, such as trading hours, news publications, or timeouts for temporarily disabling the EA trading after bad transactions. + +The datetime size in memory is 8 bytes. The internal representation of data is completely identical with the ulong type, since the quantity of seconds elapsed since January 1, 1970, is stored inside. The maximum date supported is December 31, 3000. + +The datetime constants are recorded as a literal string enclosed in single quotes, preceded by the character 'D'. 6 fields are allocated inside the string, with the numbers for all components of date and time in the following formats: + +``` +D'YYYY.MM.DD HH:mm:ss' +D'DD.MM.YYYY HH:mm:ss' + +``` + +Here, YYYY means year, MM month, DD day, HH hours, mm minutes, and ss seconds. You can skip either date or time. It is also possible not to specify seconds or minutes with seconds. + +For the maximum permitted value of date, a special constant, DATETIME_MAX, is provided in MQL5, equaling to the integer value 0x793406fff, which corresponds with  D"3000.12.31 23:59:59". + +Examples of recording the values of the datetime type are shown in file MQL5/Scripts/MQL5Book/p2/TypeDateTime.mq5. + +``` +void OnStart() +{ +  // WARNINGS: invalid date +  datetime blank = D'';           // blank = day of compilation +  datetime noday = D'15:45:00';   // noday = day of compilation + 15:45 +  datetime feb30 = D'2021.02.30'; // feb30 = 2021.03.02 00:00:00 +  datetime mon22 = D'2021.22.01'; // mon22 = 2022.10.01 00:00:00 +  // OK +  datetime dt0 = 0;                      // 1970.01.01 00:00:00 +  datetime all = D'2021.01.01 10:10:30'; // 2021.01.01 10:10:30 +  datetime day = D'2025.12.12 12';       // 2025.12.12 12:00:00 +} + +``` + +The first four variables call the compiler warning about the incorrect date. In the case of blank, the literal is completely empty. In the noday variable, there is no day. In both cases, the compiler substitutes the compilation date in the constant. Variables feb30 and mon22 contain incorrect numbers of the day and month. The compiler corrects them automatically, transferring the overflow into the higher-order field (February 30 turns into March 2, while the 22nd month becomes the 10th month of the subsequent year). However, it is always recommended to get rid of warnings. + +Variable dt0 demonstrates the initialization of the datetime value with an integer. + +Type datetime supports the set of operations inherent in integers (see [Expressions](/en/book/basis/expressions)). This, for instance, allows adding a predefined quantity of seconds to the time (obtaining a moment in the future) or computing the difference between dates. diff --git a/skills/mql5/references/book/01-basis/0023-basis-builtin-types-colors.md b/skills/mql5/references/book/01-basis/0023-basis-builtin-types-colors.md new file mode 100644 index 0000000..07820a4 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0023-basis-builtin-types-colors.md @@ -0,0 +1,26 @@ +# Color + +MQL5 has a special type for working with color. This allows the coloring of graphical objects. + +To denote the type, the color keyword is used. For the color type value, 4 bytes of memory are allocated. Its internal representation is an unsigned integer containing a color in the RGB (Red, Green, Blue) format, that is, with separate intensity levels for red, green, and blue colors. Mixing these three components allows getting any visible color shade. Green and red will produce yellow, red and blue will do purple, etc. + +1 byte is allocated for each component, that is, it can take values from 0 through 255. For instance, three zeros in all components produce a black color, while three maximum values of 255 are blended into white. + +If we present color as uint in the hexadecimal notation, then the colors are distributed as follows: 0x00BBGGRR, where RR, GG, and BB are single-byte unsigned integers. + +For its user's convenience, MQL5 supports a special form of literals to record color constants. Literal represents a triplet of numbers separated by commas and enclosed in single quotes. Character 'C' is placed before the literal. For instance, C'0,128,255' means a color with 0 for its red component, 128 for the green one, and 255 for the blue one. Hexadecimal notation of numbers can also be used: C'0x00,0x80,0xFF'. + +Besides, a long list of predefined color shades is embedded in MQL5, all starting with clr. For example, clrMagenta, clrLightCyan, and clrYellow. They also include the primaries, of course: clrRed, clrGreen, and clrBlue. The full list can be found in the MetaEditor Help. + +Below are some examples of setting colors (also available in file MQL5/Scripts/MQL5Book/p2/TypeColor.mq5): + +``` +void OnStart() +{ +  color y = clrYellow;         // clrYellow +  color m = C'255,0,255';      // clrFuchsia +  color x = C'0x88,0x55,0x01'; // x = 136,85,1 (no such predefined color) +  color n = 0x808080;          // clrGray +} + +``` diff --git a/skills/mql5/references/book/01-basis/0024-basis-builtin-types-enums.md b/skills/mql5/references/book/01-basis/0024-basis-builtin-types-enums.md new file mode 100644 index 0000000..b1cd8ce --- /dev/null +++ b/skills/mql5/references/book/01-basis/0024-basis-builtin-types-enums.md @@ -0,0 +1,85 @@ +# Enumerations + +Enumerations are a group of types built in MQL5, each containing a set of named constants to describe related concepts or properties. These constants are also referred to as enumeration elements. + +For example, enumeration ENUM_DAY_OF_WEEK contains constants for all days of the week: + +| Identifier (ID) | Description | Value | +| --- | --- | --- | +| SUNDAY | Sunday | 0 | +| MONDAY | Monday | 1 | +| TUESDAY | Tuesday | 2 | +| WEDNESDAY | Wednesday | 3 | +| THURSDAY | Thursday | 4 | +| FRIDAY | Friday | 5 | +| SATURDAY | Saturday | 6 | + +Enumeration ENUM_ORDER_TYPE describes all the order types supported in MetaTrader 5: + +| Identifier (ID) | Description | Value | +| --- | --- | --- | +| ORDER_TYPE_BUY | Market buy order | 0 | +| ORDER_TYPE_SELL | Market sell order | 1 | +| ORDER_TYPE_BUY_LIMIT | Buy Limit pending order | 2 | +| ORDER_TYPE_SELL_LIMIT | Sell Limit pending order | 3 | +| ORDER_TYPE_BUY_STOP | Buy Stop pending order | 4 | +| ORDER_TYPE_SELL_STOP | Sell Stop pending order | 5 | +| ORDER_TYPE_BUY_STOP_LIMIT | Upon reaching the order price, Buy Limit pending order is placed at the StopLimit price | 6 | +| ORDER_TYPE_SELL_STOP_LIMIT | Upon reaching the order price, Sell Limit pending order is placed at the StopLimit price | 7 | +| ORDER_TYPE_CLOSE_BY | Order for closing a position by an opposite one | 8 | + +There are a few dozens of various enumerations. Their names are prefixed with "ENUM_". We are going to learn them as we move through the relevant domain areas. + +Each enumeration is an independent type. However, their internal representation is identical, i.e., four-byte integer (int). Each enumeration constant is coded with one number or another, but in most cases, the programmer does not need to remember these numbers, since the whole point of using enumeration is exactly to replace internal representations with evident identifiers. + +The compiler ensures that the enumeration value is always one of the redefined constants. Otherwise, a warning or compilation error will occur (contextually, see the example). + +This is how the ENUM_DAY_OF_WEEK enumeration appears "underneath" (script MQL5/Scripts/MQL5Book/p2/TypeEnum.mq5). + +``` +void OnStart() +{ +  ENUM_DAY_OF_WEEK sun = SUNDAY;     // sun = 0 +  ENUM_DAY_OF_WEEK mon = MONDAY;     // mon = 1 +  ENUM_DAY_OF_WEEK tue = TUESDAY;    // tue = 2 +  ENUM_DAY_OF_WEEK wed = WEDNESDAY;  // wed = 3 +  ENUM_DAY_OF_WEEK thu = THURSDAY;   // thu = 4 +  ENUM_DAY_OF_WEEK fri = FRIDAY;     // fri = 5 +  ENUM_DAY_OF_WEEK sat = SATURDAY;   // sat = 6 +   +  int i = 0; +  ENUM_DAY_OF_WEEK x = i; // warning: implicit enum conversion +  ENUM_DAY_OF_WEEK y = 1; // ok, equals to MONDAY +  ENUM_ORDER_TYPE buy = ORDER_TYPE_BUY;   // buy = 0 +  ENUM_ORDER_TYPE sell = ORDER_TYPE_SELL; // sell = 1 +  // ... +   +  // warning: implicit conversion +  //          from 'enum ENUM_DAY_OF_WEEK' to 'enum ENUM_ORDER_TYPE' +  //          'ENUM_ORDER_TYPE::ORDER_TYPE_SELL' will be used +  //          instead of 'ENUM_DAY_OF_WEEK::MONDAY' +  ENUM_ORDER_TYPE type = MONDAY; +  // compilation error: uncomment to reproduce +  // ENUM_DAY_OF_WEEK day = ORDER_TYPE_CLOSE_BY; // cannot convert enum +  // ENUM_DAY_OF_WEEK z = 10; // '10' - cannot convert enum +} + +``` + +All constants of the days of the week are coded with numbers from 0 through 6, Sunday being the starting point. Basically, constants should not necessarily have consecutive numbers or start with 0. There are enumerations where this is not the case. + +Please note that the same constants can mean different things in different enumeration types. For instance, for orders ORDER_TYPE_BUY and ORDER_TYPE_SELL in the ENUM_ORDER_TYPE enumeration, the same values (0 and 1) are used as for the days of week SUNDAY and MONDAY in ENUM_DAY_OF_WEEK. + +When copying the value from a simple integer variable i into the enumeration variable x, the compiler gives a warning, since there can be a value other than the permitted constants in variable i at the program execution stage. + +In variable y, we record number 1 which means MONDAY, and the compiler considers this to be a correct operation. + +An attempt to write the constant of one enumeration into the variable of another enumeration (as MONDAY for variable type in the example above) may cause a warning about an implicit type conversion. This happens if the constant being written has the same value as one of the target enumeration elements. In other words, each of the two enumerations has its own element with the relevant value. Then the compiler performs an implicit conversion in the programmer's place automatically, but it uses a warning to "ask" the programmer to check whether everything is going as intended: The fact that MONDAY will be replaced with ORDER_TYPE_SELL is weird, indeed; however, we did that intentionally here for illustrative purposes. + +If the element being copied does not match by its value with any element of another enumeration, a compilation error is generated, since an implicit conversion is impossible, such as when writing ORDER_TYPE_CLOSE_BY in variable day. + +The commented string with variable z causes a compilation error, too, since the value 10 does not belong to ENUM_DAY_OF_WEEK. If the programmer is sure that, in an exotic case, there is still a need for recording a random value in the enumeration type variable, they can use explicit typecasting. + +Explicit and implicit typecasting will be discussed in the section entitled [Typecasting](/en/book/basis/conversion). + +MQL5 allows a programmer to declare their own applied enumerations using the keyword, enum. This feature is described in the next section, [Custom Enumerations](/en/book/basis/builtin_types/user_enums) (enum). diff --git a/skills/mql5/references/book/01-basis/0025-basis-builtin-types-user-enums.md b/skills/mql5/references/book/01-basis/0025-basis-builtin-types-user-enums.md new file mode 100644 index 0000000..4f5c66d --- /dev/null +++ b/skills/mql5/references/book/01-basis/0025-basis-builtin-types-user-enums.md @@ -0,0 +1,102 @@ +# Custom enumerations + +Custom enumerations are structurally based on the int type, and the principles of using them completely coincide with what has been discussed above in the preceding section dealing with embedded enumerations. Therefore, we are describing custom enumerations here, although, strictly speaking, they are not embedded. + +To describe your own enumeration in the MQL5 code, you will use the keyword enum. The simplest description form is as follows: + +``` +enum name +{ +  element1, +  element2, +  element3 +}; + +``` + +This description registers in the program an enumeration type named name with brace-enclosed comma-separated elements (their amount is only limited by the highest int value, which can be considered as no limitations in terms of practical tasks). Identifiers element1, element2, and element3 can be then used in the program within the context, in which they have been defined: Globally (i.e., outside of all functions) or inside of a function (see section [Context, visibility, and lifetime of variables](/en/book/basis/variables/scope_and_lifetime)). + +Please consider the semicolon following the closing brace. It is needed since the enumeration description is a separate statement, and semicolons must be placed after any MQL5 statement. + +By default, identifiers take constant values, starting with 0, each subsequent being 1 greater than the preceding one. If necessary, the programmer may define a specific value for each element, after '=' to the right of the identifier. For instance, the entry above is equivalent to this one: + +``` +enum name +{ +  element1 = 0, +  element2 = 1, +  element3 = 2 +}; + +``` + +It is permitted to specify as value only constants or expressions the compiler can compute at the compilation stage (for more details, please see the example below). + +If the values are not defined for all elements, the skipped values are computed automatically based on the nearest known (preceding) ones by adding 1. For example, + +``` +enum name +{ +  element1 = 1, +  element2, +  element3 = 10, +  element4, +  element5 +}; + +``` + +Here, the first two elements take values 1 and 2 (computed), while those starting with the third one take 10 (specified explicitly), 11, and 12 (the last two ones are computed based on 10). + +In script TypeUserEnum.mq5, there are some examples of describing custom enumerations. + +``` +const int zero = 0; // runtime value is not known at compile time +  +enum +{ +  MILLION = 1000000 +}; +  +enum RISK +{ +  // OFF      = zero, // error: constant expression required +  LOW      = -1, +  MODERATE = -2, +  HIGH     = -3, +}; +  +enum INCOME +{ +  LOW      = 1, +  MODERATE = 2, +  HIGH     = 3, +  ENORMOUS = MILLION, +}; +  +void OnStart() +{ +  enum INTERNAL +  { +    ON, +    OFF, +  }; +  +  // int x = LOW; // ambiguous access, can be one of +  int x = RISK::LOW; +  int y = INCOME::LOW; +} + +``` + +Enumeration INTERNAL shows the possibility of describing it inside of the function and, in doing so, limits the visibility/availability region of this type, which is useful in terms of name collisions. + +Enumeration RISK shows that elements may be assigned with negative values. Commented element OFF cannot be described due to the attempt to initialize it with a non-constant expression: In this case, variable zero is specified there, the value of which cannot be computed by the compiler. + +In enumeration INCOME, element ENORMOUS is initialized successfully by the value from the MILLION element of the other enumeration defined above. Enumerations are created at the moment of compiling and therefore, they are available in initialization expressions. + +Enumeration with MILLION has no name, such enumerations are called anonymous. Their basic application is to declare constants. However, named enumerations are used more often for constants, since they allow grouping elements by their meanings. + +Since there 2 enumerations defined in the example, both having elements with identical names, specifying the LOW identifier when declaring variable x leads to the "ambiguous access" compilation error, because it is not clear the element of which enumeration is meant. Please note that identifiers may have (and they do, in this case) different values. + +To solve this issue, there is a special context operator: Two colons, "::". They help form the complete identifier of the language element, i.e., the enumeration element, in our case: First, the enumeration name is specified, then operator "::", and after that the element identifier. Example: RISK::LOW and INCOME::LOW. We will get to know about all operators in the relevant section. diff --git a/skills/mql5/references/book/01-basis/0026-basis-builtin-types-void.md b/skills/mql5/references/book/01-basis/0026-basis-builtin-types-void.md new file mode 100644 index 0000000..94acbec --- /dev/null +++ b/skills/mql5/references/book/01-basis/0026-basis-builtin-types-void.md @@ -0,0 +1,5 @@ +# Void type + +Type void is a special type. It means emptiness (no type) and does not consume any memory. It is only used to describe functions that do not return any values or have any parameters. We learned an example of such a function: OnStart in the HelloChart script in Part 1. This will be discussed in more detail in section [Functions](/en/book/basis/functions). + +It is impossible to use type void to describe variables; however, it is the basic type in describing references to the random objects of classes. This possibility is described in [Part 3](/en/book/oop) dealing with object-oriented programming. diff --git a/skills/mql5/references/book/01-basis/0027-basis-variables.md b/skills/mql5/references/book/01-basis/0027-basis-variables.md new file mode 100644 index 0000000..7f2eed8 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0027-basis-variables.md @@ -0,0 +1,33 @@ +# Variables + +In this chapter, we will learn the basic principles of working with variables in MQL5, namely those relating to embedded data types. In particular, we will consider the declaration and definition of variables, special features of initialization as the context requires, lifetime, and basic modifiers changing the properties of variables. Later on, relying on this knowledge, we will extend the abilities of variables with new custom types (unions, custom enumerations, and aliases), classes, pointers, and references. + +Variables in MQL5 provide a mechanism for storing data of various types, playing an important role in organizing program logic and operations with market information. This section includes the following subsections: + +[Declaration and definition of variables](/en/book/basis/variables/define_vs_declare): + +- Variable declaration is the step of creating them in a program. In this section, we look at how to declare and define variables, as well as how to specify their types. + +[Context, scope, and lifetime of variables](/en/book/basis/variables/scope_and_lifetime): + +- Variables can exist in different contexts and scopes, which affects their availability and lifetime. This subsection covers these aspects, helping you understand how variables interact with your code. + +[Initialization](/en/book/basis/variables/initialization): + +- Initialization of variables involves assigning them initial values. We study methods of initialization, helping to avoid undefined program behavior. + +[Static variables](/en/book/basis/variables/static_variables): + +- Static variables retain their values between function calls. This section explains how to use static variables to store information between different code executions. + +[Constant variables](/en/book/basis/variables/const_variables): + +- Constant variables represent values that do not change during program execution. This section describes their usage and characteristics. + +[Input variables](/en/book/basis/variables/input_variables): + +- Input variables are used in trading robots to configure strategy parameters. We will see how to use them to create flexible and customizable trading systems. + +[External variables](/en/book/basis/variables/variables_extern): + +- External variables allow users to interact with the program as their values can be changed without the need to modify the code. This section explains how external variables work. diff --git a/skills/mql5/references/book/01-basis/0028-basis-variables-define-vs-declare.md b/skills/mql5/references/book/01-basis/0028-basis-variables-define-vs-declare.md new file mode 100644 index 0000000..68d3b0a --- /dev/null +++ b/skills/mql5/references/book/01-basis/0028-basis-variables-define-vs-declare.md @@ -0,0 +1,34 @@ +# Declaration and definition of variables + +A variable is a named memory cell for storing the data of a specific type. For the program to be able to operate a variable, the programmer must declare and/or define it in the source code. In the general case, the terms declaration and definition mean different things regarding the program elements, while they practically always coincide for variables. These intricacies will be covered when we get to know about functions, classes, and special (external) variables. Here we are going to use both terms interchangeably, along with the 'description' as a generalizing one. + +It would be safe to assume that a declaration contains a description of a program element with all its attributes necessary for being used in the program. Definition, however, contains the specific implementation of this element, corresponding with the declaration. + +Declarations allow the compiler to interconnect all the elements of the program. Based on definitions, the compiler generates an executable code. + +In the case of variables, their declaration practically always acts as their definition, since it ensures allocating memory and interpreting their contents in accordance with their types (this is exactly an implementation of a variable). The only exception is the declaration of variables with the word 'extern' (for more details, see section [External Variables](/en/book/basis/variables/variables_extern)). + +Only upon the description of a variable, you can use special statements to enter values into it, read them, and refer to the variable name to move it from one part of the program into another. + +In the simplest case, a statement describing a variable appears as follows: + +``` +type name; + +``` + +Here, name must meet the requirements of constructing [identifiers](/en/book/basis/identifiers). As a type, you can specify any of the [embedded types](/en/book/basis/builtin_types) that we have considered in the preceding section or some other custom types – we will learn a bit later how to create them. For example, integer variable i is declared as follows: + +``` +int i; + +``` + +If necessary, you can describe several variables of the same type simultaneously. In this case, their names are specified in the statement, separated by commas. + +``` +int i, j, k; + +``` + +An important factor is the place in the program, where the statement is located, which contains the variable description. This affects the lifetime of the variable and its accessibility from various parts of the program. diff --git a/skills/mql5/references/book/01-basis/0029-basis-variables-scope-and-lifetime.md b/skills/mql5/references/book/01-basis/0029-basis-variables-scope-and-lifetime.md new file mode 100644 index 0000000..d0ff4b1 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0029-basis-variables-scope-and-lifetime.md @@ -0,0 +1,106 @@ +# Context, scope, and Lifetime of variables + +MQL5 belongs to programming languages that use braces to group statements into code blocks. + +Recall that a program consists of blocks with statements, and one block must exist definitely. In the script samples from Part 1, we saw the OnStart function. The body of this function (the brace-enclosed text following the function name) is exactly such a necessary code block. + +Inside each block, the local context is formed, i.e., a region that limits the visibility and lifetime of variables described inside it. So far we have only encountered examples where braces define the body of functions. However, they can also be used to form [compound operators](/en/book/basis/statements/statements_compound), in the syntax of [the description of classes](/en/book/oop/classes_and_interfaces/classes_definition) and [namespaces](/en/book/oop/classes_and_interfaces/classes_namespace_context). All these methods also define visibility regions and will be considered in the relevant sections. At this stage, we only consider one type of local blocks, namely those inside of functions. + +Along local regions, every program also has one global context, i.e., a region with the definitions of variables, functions, and other entities made beyond other blocks. + +On the simple script side, in which the MQL Wizard has created the only void function OnStart, then there will only be 2 regions in it: A global one and a local one (inside the OnStart function body, although it is empty). The script below illustrates this with comments. + +``` +// GLOBAL SCOPE +void OnStart() +{ +  // LOCAL SCOPE "OnStart" +} +// GLOBAL SCOPE + +``` + +Please note that the global region stretches everywhere apart from function OnStart (both before and after it). Basically, it includes everything beyond any functions (if there were many), but there is nothing in this script, apart from OnStart. + +We can describe variables, such as i, j, k, on the top of the file, and they will become global. + +``` +// GLOBAL SCOPE +int i, j, k; +void OnStart() +{ +  // LOCAL SCOPE "OnStart" +} +// GLOBAL SCOPE + +``` + +Global variables are created immediately upon starting an MQL program in the terminal and exist for the entire period of program execution. + +The programmer can record and read the contents of global variables from any place in the program. + +It is basically recommended to describe global variables just at the top, but it is necessary. If we move the declaration below the entire function OnStart, nothing will change basically. It will just be difficult for other programmers to immediately make sense of the code with variables, the definitions of which one has still to get to. + +Interestingly, the OnStart function itself is declared in the global context, too. If we add another function, it will also be declared in the global context. Recall how we created the Greeting function in Part 1 and called it from the OnStart function. This is the effect of the function name and the method of referencing to it (how to execute it) being known throughout the source code. [Namespaces](/en/book/oop/classes_and_interfaces/classes_namespace_context) add some niceties to it; however, we will learn them later. + +A local region inside each function only belongs to it: One local region is inside OnStart, and another is inside Greeting, which is its own and differs from both the local region of OnStart and the global one. + +Variables described in the function body are called local. They are created according to their descriptions as of calling the relevant function during the program execution. Local variables can be only used inside the block that contains them. They are not visible or accessible from the outside. When leaving the function, local variables are destroyed. + +Example of describing local variables x, y, z inside function OnStart: + +``` +// GLOBAL SCOPE +int i, j, k; +void OnStart() +{ +  // LOCAL SCOPE "OnStart" +  int x, y, z; +} +// GLOBAL SCOPE + +``` + +It should be noted that pairs of braces can be used in both describing the function and other statements and as themselves to form the internal code block. Unit nesting is unlimited. + +Nested blocks are usually added to minimize the scope of variables used in a logically isolated small code location (if it is not set by a function for one reason or another). This allows the reduction of the probability of a false modification of the variable where it was not provided for or some undesired side effects due to the attempt to re-purpose the same variable for various needs (it is not a good practice). + +Below is a sample function where unit nesting level is 2 (if we consider the block with the function body to be the first level), and 2 such blocks are created and will be executed consecutively. + +``` +void OnStart() +{ +  // LOCAL SCOPE "OnStart" +  int x, y, z; +   +  {  +    // LOCAL SUBSCOPE 1 +    int p; +    // ... use p for task 1 +  } +   +  {  +    // LOCAL SUBSCOPE 2 +    // y = p; // error: 'p' - undeclared identifier +    int p;    // from now 'p' is declared +    // ... use p for task 2 +  } +   +  // p = x; // error: 'p' - undeclared identifier +} + +``` + +Inside both blocks, variable p is described, which is used for various purposes in them. In fact, these are two different variables, although having the same name visible inside each block. + +If the variable were taken out to the initial list of the local variables of the function, it could contain some remaining value upon exiting from the first block, thus breaking the operation of the second block. Moreover, the programmer could occasionally involve p in something else at the very beginning of the function, and then the side effects could take place in the first block. + +Beyond either of the two nested blocks, variable p is unknown and therefore, an attempt to refer to it from the common block of the function leads to a compilation error ("undeclared identifier"). + +It should also be noted that a variable can be described not at the very beginning of the block, but in its middle or even closer to the end. Then it is defined not throughout the block, but only below its definition. Therefore, when referring to the variable above its description, the same error will occur. + +Thus, the variable scope region may differ from the context (the entire block). + +Both versions of the problem are illustrated in an example: Try to include any of the strings with statements p = x and y = p and compile the source code. + +Memory is allocated for all the local variables of the function as soon as the control is passed inside the function. However, this is not the end of their creation. Then they are initialized (initial values are set), initialization being defined explicitly by the programmer or implicitly by the default values of the compiler. At the same time, context is of the essence, in which the variables are described. diff --git a/skills/mql5/references/book/01-basis/0030-basis-variables-initialization.md b/skills/mql5/references/book/01-basis/0030-basis-variables-initialization.md new file mode 100644 index 0000000..4d6ff84 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0030-basis-variables-initialization.md @@ -0,0 +1,121 @@ +# Initialization + +In describing variables, there is a possibility to set the initial value; it is specified following the variable name and symbol '=' and must correspond with the variable type or be cast to it (typecasting can be found in the relevant [section](/en/book/basis/conversion)). + +``` +int i = 3, j, k = 10; + +``` + +Here i and k are initialized explicitly, while j is not. + +Both a constant (literal of the relevant type) and an expression (a kind of formula for calculations) can be specified as the initial value. We will set out [expressions](/en/book/basis/expressions) separately. In the meantime, a simple example: + +``` +int i = 3, j = i, k = i + j; + +``` + +Here, variable j takes the same value as variable i, while variable k takes the sum of i and j. Strictly speaking, in all three cases, we see expressions here. However, constant (3) is a special, degenerate expression option. In the second case, the only variable name is an expression, i.e., the expression result will be the value of this variable without any transformations. In the third case, two variables, i and j, are accessed in the expression, the addition operation is executed with their values, and after that, the result gets into variable k. + +Since the statement containing the description of several variables is processed from left to right, the compiler already knows the names of previous variables when analyzing yet another description. + +A program usually contains many statements with variable descriptions. They are read by the compiler in a natural top-down manner. In later initializations, names can be used taken from earlier descriptions. Here are the same variables described by two separate statements. + +``` +int i = 3, j = i; +int k = i + j; + +``` + +Variables without an explicit initialization also get some initial values, but they depend on the place where the variable was described, i.e., on its context. + +Where there is no initialization, local variables take random values at the moment of their generation: The compiler just allocates memory for them according to the type size, while it is unknown what will be at a specific address (various computer memory areas are often re-allocated to be used in different programs after they have become unnecessary for those executed earlier). + +It is usually suggested that working values will be entered in local variables without initialization somewhere later in the algorithm code, such as using [assignment operations](/en/book/basis/expressions/operator_assignment) we will talk about later on. Syntactically, it is similar to initialization, since it also uses the equal sign, '=', to transfer the value from the "structure" placed on the right of it (it can be a constant, variable, expression, or function call, into the variable on the left. Only a variable can be to the left of '='. + +The programmer should ensure that reading from the uninitialized variable only takes place upon a meaningful value is assigned to it. Compiler gives a warning if this is not the case ("possible use of uninitialized variable"). + +Everything is different with global variables. + +An example of global variables is the GreetingHour input parameter of the GoodTime2 script from Part 2. The fact that the variable was described with keyword input does not affect its other properties as a variable. We could exclude its initialization and describe it as follows: + +``` +input uint GreetingHour; + +``` + +This would not change anything in the program, because global variables are implicitly initialized by the compiler using zero if there is no explicit initialization (while we also had explicit initialization with zero before). + +Whatever the variable type is, implicit initialization is always performed by a value equivalent to zero. For example, for a bool variable, false will be set, while for a datetime variable there will be D'1970.01.01 00:00:00'. There is a special value, NULL, for strings. It is, if you like, an even "emptier" string than empty quotes "" because there is still some memory allocated for them, where the only terminal null character is placed. + +Along with local and global variables, there is another type, i.e., static variables. The compiler initializes them with zero implicitly, too, if the programmer has not written an explicitly initial value. They will be considered in the [next section](/en/book/basis/variables/static_variables). + +Let's create a new script, VariableScopes.mq5, with examples of describing local and global variables (MQL5/Scripts/MQL5Book/VariableScopes.mq5). + +``` +// global variables +int i, j, k;    // all are 0s +int m = 1;      // m = 1                (place breakpoint on this line) +int n = i + m;  // n = 1 +void OnStart() +{ +  // local variables +  int x, y, z; +  int k = m; // warning: declaration of 'k' hides global variable +  int j = j; // warning: declaration of 'j' hides global variable +  // use variables in assignment statements   +  x = n;     // ok, 1 +  z = y;     // warning: possible use of uninitialized variable 'y' +  j = 10;    // change local j, global j is still 0 +} +// compilation error +// int bad = x; // 'x' - undeclared identifier + +``` + +It should be remembered that, at launching an MQL program, the terminal first initializes all global variables and then calls a function that is the starting point for the programs of a relevant type. In this case, it is OnStart for scripts. + +Here, only variables i, j, k, m, n are global since they are described outside the function (in our case, we only have one function, OnStart, which is necessary for scripts). i, j, k take the value of 0 implicitly. m and n contain 1. + +You can run the script in the debugging mode on a step-by-step basis and make sure that the values of variables change exactly in this manner. For this purpose, you should preliminarily set a [breakpoint](https://www.metatrader5.com/en/metaeditor/help/development/debug#breakpoint) onto the string with the initialization of one of the global variables, such as m. Put the text cursor onto this string and execute Debug -> Toggle Breakpoint (F9), and the string will be highlighted with a blue sign in the left field, which signals that the program execution will stop here if it starts working on the debugger. + +Then you should actually run the program for debugging, for which purpose execute command Debug -> Start on real data (F5). At this moment, a new chart will open in the terminal, in which this script starts being executed (caption "VariableScopes (Debugging)" in the upper right corner), but it suspends immediately, and we get back to MetaEditor. We should see a picture in it as follows. + +![Step-by-step debugging and viewing variables in MetaEditor](pics/me_breakpoint_en.png) + +Step-by-step debugging and viewing variables in MetaEditor + +A string containing a breakpoint is now marked with an arrow sign — it is the current statement the program is preparing to execute but has not executed yet. The current stack of the program is shown lower left, which consists so far of only one entry: @global_initializations. You can enter expressions lower right to monitor their real-time values. We are interested in the values of variables; therefore, let's consecutively enter i, j, k, m, n, x, y, z (each in a separate string). + +You will see further that MetaEditor automatically adds variables from the current context for viewing (for instance, local variables and the function inputs, where statements are executed inside the function). But now, we are going to add x, y, and z manually and in advance, just to show that they are not defined outside the function. + +Please note that, for local variables, it is written "Unknown identifier" instead of a value, because there has not been the OnStart function block yet, where they are located. Global variables i and j will first have zero values. Global variable k is not used anywhere and, therefore, it is excluded by the compiler. + +If we execute one step of the program execution (execute the statement on the current code line) using commands Step Into (F11) or Step Over (F10), we will see how variable m takes value 1. Another step will continue initialization for variable n, and it will also become 1. + +Here, the descriptions of global variables end and, as we know, terminal calls function OnStart upon completion of the initialization of global variables. In this case, to step into function OnStart in the stepwise mode, press F11 once again (or you can set another breakpoint in the beginning of the OnStart function). + +Local variables are initialized when the execution of the program statements reaches the code block where they have been defined. Therefore, variables x, y, z are only created upon stepping into the OnStart function. + +When the debugger gets inside the OnStart function, with a little luck, you will be able to see that there are really initially random values in x, y, and z. "Luck" here consists in the fact that these random values may well be zero ones. Then it will be impossible to differ them from the implicit initialization with zero, compiler performs for global variables. If the script is launched repeatedly, the "garbage" in local variables will likely be different and more illustrative. They are not initialized explicitly and, therefore, their contents may be of any kind. + +In the sequence of images below, you can see the evolution of variables using the step-by-step mode of the debugger. The current string to be executed (but not executed yet) is marked with a green arrow on the fields with enumeration. + +![Step-by-step debugging and viewing variables in MetaEditor (string 23)](pics/debug23_en.png) + +Step-by-step debugging and viewing variables in MetaEditor (string 23) + +![Step-by-step debugging and viewing variables in MetaEditor (string 24)](pics/debug24_en.png) + +Step-by-step debugging and viewing variables in MetaEditor (string 24) + +It is demonstrated further in the code how these variables could be used in the simplest manner in assignment operators. The value of the global variable n is copied into the local x without any problems since n has been initialized. However, in the string where the contents of variable y are copied to variable z, a warning from the compiler appears, because y is local and, as of this moment, nothing has been written in it; i.e., there is not an explicit initialization, as well as other operators that can set its value. + +Inside a function, it is permitted to describe variables with the same names as already used for global variables. A similar situation may occur in nested local blocks if a variable is created in an internal block with the name existing in an external block. However, this practice is not recommended, since it may lead to logical errors. In such cases, the compiler gives a warning ("declaration hides global/local variable"). + +Due to such redefining, a local variable, such as k in the example above, overlaps the homonym global one inside the function. Although they have the same name, these are two different variables. Local k is known inside OnStart, while global k is known everywhere apart from OnStart. In other words, any inside-the-block operations with variable k will only affect the local variable. Therefore, upon exiting function OnStart (as if it were not the only and core function of the script), we would discover that global variable k is still equal to zero. + +Local variable j does not only overlap global variable j but is also initialized by the value of the latter one. In the string containing the description of j inside OnStart, the local version of j is still being created when the initial value for it is read from the global version of j. Upon a successful definition of local j, this name overlaps the global version, and it is the local version, to which the subsequent changes in j belong. + +At the end of the source code, we have commented on the attempt to declare one more global variable, bad, in the initialization of which the value of variable x is called. This string causes a compiler error since variable x is unknown beyond the OnStart function, in which it has been defined. diff --git a/skills/mql5/references/book/01-basis/0031-basis-variables-static-variables.md b/skills/mql5/references/book/01-basis/0031-basis-variables-static-variables.md new file mode 100644 index 0000000..887ecee --- /dev/null +++ b/skills/mql5/references/book/01-basis/0031-basis-variables-static-variables.md @@ -0,0 +1,79 @@ +# Static variables + +It is sometimes necessary to describe a variable inside a function, ensuring its existence for the entire duration of the program execution. For example, we want to count how many times this function has been called. + +Such a variable cannot be local, because then it will lose its "long memory," since it will be created every time at calling the function and removed at exiting it. Technically, it could be described globally; however, if the variable is only used in this function, this approach is wrong in terms of program design. + +First, a global variable can accidentally be changed from any place in the program. + +Second, imagine what "zoo" of variables would be made in the global region of the program if we declare a global variable at the slightest pretext. Instead, it is recommended to declare variables in the smallest block (if there are several nested ones), in which they are used. + +Therefore, the counter of function executions should be described inside the function. This is where the new attribute of variables helps, their static nature. + +A special keyword (modifier), static, placed before the variable type in its declaration allows prolonging its lifetime up to the entire duration of program execution, that is, makes it similar to global ones. As a rule, a static variable is only defined locally, in one of the functions. Therefore, its visibility is limited by the relevant code block, as in a normal local variable. + +Static variables can also be described at a global level, but do not differ from the normal global ones in any way (at least, as of writing this book). It varies from their behavior in C++: There, their visibility is limited by the file they are described in. In MQL5, a program is assembled based on one main mq5 file and, perhaps, some header files (see [directive ](/en/book/basis/preprocessor/preprocessor_include)[#include](/en/book/basis/preprocessor/preprocessor_include)); therefore, both static and normal global variables are available from all source files of the program. + +A local static variable is created only once — at the moment when the program first steps into the function where this variable is described. Such a variable will only be removed at unloading the program. If a function has never been called, the local static variables described in it, if any, will never be created. + +As an example, let's modify the Greeting function from Part 1 so that it gives different greetings at each call. Let's name the new script GoodTimes.mq5. + +We will remove the input of the script GreetingHour and the parameter of the Greeting function. Inside the Greeting function, we will describe a new static variable, counter, of integer type, with the initial value of 0. It should be reminded that it is exactly initialization, and it will be executed only once because the variable is static. + +``` +string Greeting()  +{ +  static int counter = 0; +  static string messages[3] = +  { +    "Good morning", "Good day", "Good evening" +  }; +  return messages[counter++ % 3]; +} + +``` + +Since we know modifier static now, it is reasonable to also use it for array messages. The matter is that it was declared as local before, and it would be re-created every time at multiple calls of function Greeting (and removed at exit). This is not efficient. + +It should be reminded that an array is a named set of several values of the same type, available by index specified in square brackets after the name. Much of what has been said about variables applies directly to arrays. Further nuances of working with arrays will be covered in section [Arrays](/en/book/basis/arrays). + +But let's get back to our current problem. An option is chosen from the array based on the value of the counter variable in the return statement and so far appears quite cabbalistically: + +``` +  return messages[counter++ % 3]; + +``` + +We have already mentioned casually the modulus operation performed using character '%' in Part 1. With it, we guarantee that the element index will not be able to exceed the array size: Whatever be counter, its division modulo by 3 will either be 0 or 1, or 2. + +The same applies to structure counter++, it means adding 1 to the variable value (single increment). + +It is important to note that, in this notation, incrementation will take place upon having computed the entire expression, in this case, upon division counter % 3. This means that counting will start from zero, i.e., initial value. There is a possibility to make an increment before computing the expression, having written: ++counter % 3. Then counting would start from 1. We will consider the operations of this type in section [Increment and Decrement](/en/book/basis/expressions/increment_decrement). + +Let's call the Greeting function from OnStart 3 consecutive times. + +``` +void OnStart() +{ +  Print(Greeting(), ", ", Symbol()); +  Print(Greeting(), ", ", Symbol()); +  Print(Greeting(), ", ", Symbol()); +  // Print(counter); // error: 'counter' - undeclared identifier +} + +``` + +As a result, we will see the anticipated three strings with all greetings one after another in the log. + +``` +GoodTimes (EURUSD,H1)        Good morning, EURUSD +GoodTimes (EURUSD,H1)        Good afternoon, EURUSD +GoodTimes (EURUSD,H1)        Good evening, EURUSD + +``` + +If we continue calling the function, the counter will increase, and the messages will rotate. + +An attempt to refer to the counter variable at the end of OnStart (commented) will not allow the code to be compiled, since the static variable, although it continues to exist, is only available inside function Greeting. + +Please note that braces are used for both forming the code blocks and initializing arrays. You should distinguish among their applications. Arrays will be considered in detail in the relevant section. However, these are not all applications of braces: Using them, we will later learn how to define custom types, structures, and classes. Static variables can also be defined inside structures and classes. diff --git a/skills/mql5/references/book/01-basis/0032-basis-variables-const-variables.md b/skills/mql5/references/book/01-basis/0032-basis-variables-const-variables.md new file mode 100644 index 0000000..a5bff54 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0032-basis-variables-const-variables.md @@ -0,0 +1,30 @@ +# Constant variables + +However paradoxically this appears, most programming languages support the concept of constant variables. In MQL5, they are described by adding modifier const. It is placed in the variable description, preceding its type, and means that the variable value cannot be changed in any way upon its initialization by the initial value. During its entire lifetime, the variable will have the same value, i.e., a constant. + +The compiler will just prevent assigning the constant with a value: The error "constant cannot be modified" will appear in the relevant string. + +Modifier const is aimed at explicitly showing the programmer's intention not to change the relevant variable, if a commonly known fixed value, such as the EUR index to compute the USD index, the number of weeks in a year, etc. It is recommended to always use modifier const if you are not going to change the variable. This helps avoid potential errors later, if the programmer themselves or somebody from among their colleagues accidentally tries to write something else into the constant. + +For example, we can add modifier const for the messages array in the Greeting function. This does not appear plainly useful for such a small program. However, since programs tend to grow out, any string may sooner or later "find itself" in a much more complex software environment, such as added statements, operation modes, etc. Therefore, it makes sense to have a plan B; particularly as it is so simple. + +``` +string Greeting()  +{ +  static int counter = 0; +  static const string messages[3] = +  { +    "Good morning", "Good day", "Good evening" +  }; +  // error demo: 'messages' - constant cannot be modified +  // messages[0] = "Good night"; +  return messages[counter++ % 3]; +} + +``` + +In the commented string, we test recording the "Good night" string into the first element of the array (remember that numbering starts from 0). In this case, the sense of this action is just to make sure that the compiler prevents from doing that. + +As is easily seen, modifiers static and const can be combined. The order of recording them is not important. + +By the way, in MQL5, variables become constants in both using modifier const and declaring them with the input variables of the program. diff --git a/skills/mql5/references/book/01-basis/0033-basis-variables-input-variables.md b/skills/mql5/references/book/01-basis/0033-basis-variables-input-variables.md new file mode 100644 index 0000000..f8e5a36 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0033-basis-variables-input-variables.md @@ -0,0 +1,51 @@ +# Input variables + +When launched, all programs in MQL5 can inquire parameters from the user. The only exception is libraries that are not executed independently, but as parts of another program (see the relevant section to know more about [Libraries](/en/book/advanced/libraries)). + +Input parameters of MQL programs are global variables described in the code having a special modifier of input or sinput. They become available in the dialog of program properties for the user to enter values. We saw a description of the GreetingHour input variable in the scripts of Part 1. + +A special feature of input variables is the fact that their value cannot be changed in the program code, i.e., it behaves like a constant. + +Input variables can only be of simple built-in types or enumerations. For enumerations, you enter the values via a drop-down list; while you use input fields in all other cases. It is not permitted to describe as input: [Arrays](/en/book/basis/arrays), [structures or unions](/en/book/oop/structs_and_unions), and [classes](/en/book/oop/classes_and_interfaces). + +The developer can set the input parameter name other than the variable identifier. This name will be shown to the user in the program properties dialog. A detailed description should be added as a sing-string comment upon the definition of the input parameter. + +``` +input int HourStart = 0; // Start of trading (hour, including): +input int HourStop = 0;  // End of trading (hour, excluding): + +``` + +This allows making the interface user-friendlier, detailed, and free of syntactic constraints imposed by MQL5 on [identifiers](/en/book/basis/identifiers). Moreover, names (as well as comments) can be in your native language. + +For example, MetaTrader 5 comes with the source code of indicator MQL5/Indicators/Examples/Custom Moving Average.mq5 with input variables: + +``` +input int            InpMAPeriod = 13;        // Period +input int            InpMAShift  = 0;         // Shift +input ENUM_MA_METHOD InpMAMethod = MODE_SMMA; // Method + +``` + +This description generates the properties dialog below. + +![Sample dialog of the MQL program properties](pics/inputs-en.png) + +Sample dialog of the MQL program properties + +The maximum length of the text representation of an input variable as an identifier=value pair, including character "=", may not exceed 255 characters (This constraint is imposed by the internal data exchange protocols of the terminal and testing agents). This limit is especially important for string variables since the values of other types never go beyond it. As we know, the length of an identifier is limited to 63 characters; therefore, depending on the identifier length, 191-253 characters are left for the value of the input string variable. The entire text exceeding the combined threshold of 255 chars may be cropped when being transferred to the tester. If a longer string has to be entered into your MQL program, use multiple input fields (to be continued) or allow the user to specify the name of the file, from which the text should be read. + +For convenience in operating MQL programs, inputs can be combined in named blocks using keyword group (semicolon in the group string end is not necessary). + +``` +input group "group_name" +input type identifier = value; +... + +``` + +All variables with modifier input following the group description (up to the description of another group or to the file end) are visually displayed as a nested list under the group header in the properties dialog of the MQL program. Moreover, groups of parameters can be deployed or collapsed by a mouse click in the strategy tester applicable to both indicators and EAs. + +The sinput keyword is the abbreviation of static input, both forms being equivalent. + +Variables described with modifiers sinput and static input cannot be involved in optimization. It only makes sense to use them in Expert Advisors being the only MQL program type supporting optimization. For more details, see the section dealing with [Testing and optimizing Expert Advisors](/en/book/automation/tester). diff --git a/skills/mql5/references/book/01-basis/0034-basis-variables-variables-extern.md b/skills/mql5/references/book/01-basis/0034-basis-variables-variables-extern.md new file mode 100644 index 0000000..e9e3bf7 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0034-basis-variables-variables-extern.md @@ -0,0 +1,144 @@ +# External variables + +The material in this section is simultaneously complex and optional. It requires the knowledge of the concepts that are based on the analogy to C++ and those considered hereinbelow. At the same time, the effect of the language structure described can be achieved in another manner, while its flexibility is a potential source of errors. + +MQL5 allows describing variables as external ones. This is made using the extern keyword and is only permitted in the [global context](/en/book/basis/variables/scope_and_lifetime). + +For an external variable, syntax basically repeats a normal description but it additionally has the 'extern' keyword while initialization is prohibited: + +``` +extern type identifier; + +``` + +Describing a variable as external means that its description is delayed and must occur later in the source code, usually in another file (connecting files using the [#include](/en/book/basis/preprocessor/preprocessor_include)[ directive](/en/book/basis/preprocessor/preprocessor_include) will be considered in the chapter dealing with the [preprocessor](/en/book/basis/preprocessor)). Several different source files can have a description of the same external variable, that is, those having identical types and identifiers. All such descriptions refer to the same variable. + +It is assumed that this variable will be completely described in one of the files. If the variable is not defined anywhere in the code without the extern keyword, the "unresolved extern variable" compilation error is returned (similar to a linker error in C++ in such cases). + +Describing an external variable allows using it efficiently in the source code of a particular file. In other words, it enables compiling a given module, although the variable is not created in this module. + +Using extern in MQL5 is not so insistent as in C++ and in most cases, may be replaced by enabling a header file with general descriptions of the variables to be declared as extern. It is sufficient to perform these definitions conventionally. The compiler ensures adding each attached file to the source code only once. Considering that in MQL5 a program always consists of one compilable unit mq5, there is no C++ problem here, with the potential error of the multiple definitions of the same variable due to enabling the header in different units. + +Even an additional mq5 (not mqh) file is attached in the #include directive, it does not equally compete with the main unit, for which compilation is launched; instead, it is considered as one of the headers. + +Unlike C++, MQL5 does not allow specifying an initial value for an external variable (initialization in C++ leads to ignoring the word extern). If you try to set an initial value, you will get a compilation error "extern variable initialization is not allowed". + +Generally, describing a variable as external can be considered a kind of "soft" description: It ensures the appearance of the variable and excludes the overriding error that would occur if the variable is described in several files without the extern modifier. + +However, this can be a source of errors. If in different header files, by coincidence, identical variables are described for different purposes, then no keyword extern allows identifying a collision, while with extern, the variables will become one, and the program operation logic will most likely be broken. + +As external, both variables and functions can be described (they will be considered [below](/en/book/basis/functions)). For functions, describing them with the attribute as external is a rudiment (i.e., it is compiled, but does not make any changes). The following two declarations of a function are equivalent: + +``` +extern return_type name([parameters]); +      return_type name([parameters]); + +``` + +In this sense, the presence/absence of extern can only be used to stylistically distinguish between a forward description of a function from the current unit (no extern) or from an external one (extern is present). + +You can use extern in both the mq5 unit to be compiled and header files to be attached. + +Let's consider some options for using extern: They are entered in different files, i.e., main script ExternMain.mq5 and 3 attachable files: ExternHeader1.mqh, ExternHeader2.mqh, and ExternCommon.mqh. + +In the main file, only ExternHeader1.mqh and ExternHeader2.mqh are attached, while we will need ExternCommon.mqh a bit later. + +``` +// source code from mqh files will be substituted implicitly +// in the main mq5 file, instead of these directives +#include "ExternHeader1.mqh" +#include "ExternHeader2.mqh" + +``` + +In header files, two conditionally useful functions are defined: In the first one, function inc for the x variable increment, while in the second, function dec for the x variable decrement. It is variable x that is described in both files as external: + +``` +// ExternHeader1.mqh +extern int x; +void inc() +{ +   x++; +} +// ----------------- +// ExternHeader2.mqh +extern int x; +void dec() +{ +   x--; +} + +``` + +Due to this description, each of the mqh files is compiled in a regular way. When they are included in an mq5 file together, the entire program is compiled, too. + +If the variable were defined in each file without the word extern, the re-defining error would occur in compiling the program as a whole. If we had transferred the definition of x from header files into the main unit, header files would have stopped being compiled (it is not a problem for somebody, perhaps; however, in larger programs, developers like checking the compilation ability of immediate corrections without compiling the entire project). + +In the main script, we define a variable (in this case, with an initial value of 2, while if we do not specify the value, the default 0 will be used) and call the conditionally useful functions, as well as print the x value. + +``` +int x = 2; +    +void OnStart() +{ +   inc();  // uses x +   dec();  // uses x +   Print(x); // 2 +   ... +} + +``` + +In file ExternHeader1.mqh, there is the description of variable short z (without extern). A similar description is commented upon in the main script. If we make this string active, we will get the error mentioned before ("variable already defined"). This is done to illustrate the potential problem. + +In ExternHeader1.mqh, extern long y is described, too. At the same time, in file ExternHeader2.mqh, the homonym external variable has another type: extern short y. If the latter description were not "moved" into a comment preemptively, the types incompatibility error ("variable 'y' already defined with different type") would occur here. Summary: Either types must coincide or variables must not be external. If both options are not good, it means that there is a mistype in the name of one of the variables. + +Moreover, it should be noted that variable y is not explicitly initialized. However, the main script calls it successfully and prints 0 in the log: + +``` +long y; +    +void OnStart() +{ +   ... +   Print(y); // 0 +} + +``` + +Finally, there is a possibility provided in the script to try an alternative of the external twin variables, exemplified by the already known variable x. Instead of describing extern int x, each of the files ExternHeader1.mqh and ExternHeader2.mqh can include another common header, ExternCommon.mqh, in which there is the description of int x (without extern). It becomes the only description of x in the project. + +This alternative mode of assembling the program is enabled when activating [macro](/en/book/basis/preprocessor/preprocessor_define_simple) USE_INCLUDE_WORKAROUND: It is in the comment at the beginning of the script: + +``` +#define USE_INCLUDE_WORKAROUND // this string was in the comment +#include "ExternHeader1.mqh" +#include "ExternHeader2.mqh" + +``` + +In this configuration, particular include files will still be compilable, as well as the entire project. In a real project, without using this method, the common mqh file would be included in ExternHeader1.mqh and ExternHeader2.mqh unconditionally (no USE_INCLUDE_WORKAROUND conditions). In this example, switching between the two threads of instructions is based on USE_INCLUDE_WORKAROUND is only needed to demonstrate both modes. For example, the simplified version of ExternHeader2.mqh should appear as follows: + +``` +// ExternHeader2.mqh +#include "ExternCommon.mqh" // int x; now here +  +void dec() +{ +   x--; +} + +``` + +We can check in the MetaEditor log that file ExternCommon.mqh loaded only once, although it is referenced in both ExternHeader1.mqh and ExternHeader2.mqh. + +``` +'ExternMain.mq5' +'ExternHeader1.mqh' +'ExternCommon.mqh' +'ExternHeader2.mqh' +code generated + +``` + +If the x variable is "registered" in ExternCommon.mqh, we shall not re-define it (without extern) in the main unit since this would cause a compilation error, but we can simply assign to it the desired value at the beginning of the algorithm. diff --git a/skills/mql5/references/book/01-basis/0035-basis-arrays.md b/skills/mql5/references/book/01-basis/0035-basis-arrays.md new file mode 100644 index 0000000..15d16e0 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0035-basis-arrays.md @@ -0,0 +1,7 @@ +# Arrays + +An array is a tool for cluster-based storing and processing the data of random types. They are supported practically in any programming language. They are especially important in MQL5 because they represent a convenient method of arranging serial data relevant to trading tasks. Quotes, readings of indicators, account trading history with orders and transactions, and news are all examples of serial data, that is, the sequences of time-varying values. + +The array can be considered a container variable: It can contain a predefined quantity of values of the same type, which are identified by both their name and index (position number). + +In this section, we are going to consider the common syntax of describing arrays and calling them, exemplified by [embedded data types](/en/book/basis/builtin_types). In the subsequent parts of this book, with acquiring information on how to extend the system of types due to the object-oriented technology, we will use arrays in conjugation with them to get new opportunities. diff --git a/skills/mql5/references/book/01-basis/0036-basis-arrays-arrays-overview.md b/skills/mql5/references/book/01-basis/0036-basis-arrays-arrays-overview.md new file mode 100644 index 0000000..348b407 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0036-basis-arrays-arrays-overview.md @@ -0,0 +1,36 @@ +# Array characteristics + +Before giving an account of the syntactic particulars of declaring arrays in MQL5 and practices of working with them, let's consider some basic concepts of constructing the arrays. + +The core characteristic of an array is the number of dimensions. In a one-dimension array, its elements are placed one by one, like a row of soldiers, and just one number (index) is sufficient to refer to them. Bar-by-bar prices of opening a financial instrument to the given history depth can be saved in such an array. + +In a two-dimensional array, its elements diverge in two logically perpendicular directions, forming a kind of a square (or rectangular, in a general case), two indices being required for each element, i.e., one in each dimension. Such an array could be used to store price quads (Open, High, Low, and Close) for each history bar. Bar numbers would be counted with the first dimension, while the second one is used for numbers from 0 through 3, denoting one of the price types. + +A three-dimensional array is the equivalent of a cube (or, more strictly in terms of geometry, right-angled parallelepiped) with three axes. Continuing the example with the array of bar-by-bar prices, we could add to it the third dimension responsible for iterating financial instruments from the Market Watch. + +For each dimension, the array has a certain length (size) setting the range of possible indexes. If history is supposed to be loaded for 1,000 bars and 10 instruments, we would get an array sized 1,000 elements in the first dimension, 4 elements in the second one (OHLC), and 10 in the third one. + +The product of sizes in all dimensions provides the total number of the array elements; in our case, it is 40,000. In MQL5, it may not exceed 2147483647 (maximum for int). + +It is already difficult to imagine a solid shape for a 4-dimensional array because we live in a 3D world. However, MQL5 permits the creation of arrays having up to four dimensions. + +It should be noted that you can always use a one-dimensional array instead of a multidimensional one with a random number of dimensions, including more than 4. This is just a matter of arranging the recomputing of several indexes into a continuous one. For example, if a two-dimensional array has 10 columns (dimension 1, axis X) and 5 rows (dimension 2, axis Y), it can be transformed into a one-dimensional array with the same quantity of elements, i.e., 50. In this case, the element index will be obtained by the following formula: + +``` +index = Y * N + X + +``` + +Here, N is the number of elements in the first dimension, in our case, 10; it is the size of each row; Y is the row number (0..4); and X is the column number (0..9) in the row. + +Sizes across dimensions are another characteristic that separates an array from a variable. Thus, the number of dimensions and size in each dimension must be specified in some manner in the description, along with the array name and data type (see [the following section](/en/book/basis/arrays/arrays_declaration)). + +You should distinguish between the size of a variable (array element) in bytes and that of an array as the number of elements in it. Theoretically, the full array size in terms of memory it consumes must be the product of the size of one element (depending on the data type) and the number of elements. However, this formula does not always work in practice. Particularly, since strings may have different lengths, it is quite difficult to evaluate the memory volume consumed by a string array. + +According to the memory allocation method, arrays can be dynamic or fixed-size. + +A fixed-size array is described in the code with exact sizes in all dimensions. It is impossible to resize it later. However, practical tasks often occur, in which the amount of data to be processed is contingent and therefore, it is desirable to resize the array during the algorithm operation. Dynamic arrays exist for this particular purpose. As we will see further, they are described without specifying the first-dimension size and can then be "stretched" or "compacted" using the special MQL5 API functions. + +MQL5 Documentation uses ambiguous terminology that names fixed-size array static. This concept is also used for the 'static' modifier that can be applied to the array. If such an array is declared dynamic, then it is simultaneously non-static in terms of memory allocation and static in terms of the 'static' modifier. To exclude ambiguousness, the static character in this book will only mean the declaration attribute. + +Along with dynamic and fixed-size arrays, there are special arrays in MQL5 to store quotes and the buffers of technical indicators. Such arrays are named timeseries arrays since their indexes correspond with timing. In fact, these arrays are one-dimensional and dynamic. However, unlike other dynamic arrays, the terminal itself allocates memory for them. We will consider them in the sections dealing with [timeseries](/en/book/applications/timeseries) and [indicators](/en/book/applications/indicators_make). diff --git a/skills/mql5/references/book/01-basis/0037-basis-arrays-arrays-declaration.md b/skills/mql5/references/book/01-basis/0037-basis-arrays-arrays-declaration.md new file mode 100644 index 0000000..e5ef8bb --- /dev/null +++ b/skills/mql5/references/book/01-basis/0037-basis-arrays-arrays-declaration.md @@ -0,0 +1,127 @@ +# Description of arrays + +Array description inherits some features of variable descriptions. To start with, we should note that arrays may be global and local, based on the place of their declaration. Similarly to variables, modifiers const and static can also be used in describing an array. For a one-dimension fixed-size array, the declaration syntax appears as follows: + +``` +type static1D[size]; + +``` + +Here, type and static1D denote the type name of elements and the array identifier, respectively, while size in square brackets is a size-defining integer constant. + +For multidimensional arrays, several sizes must be specified, according to the quantity of dimensions: + +``` +type static2D[size1][size2]; +type static3D[size1][size2][size3]; +type static4D[size1][size2][size3][size4]; + +``` + +Dynamic arrays are described in a similar manner, except that a skip is made in the first square brackets (before using such an array, the required memory volume must be allocated for it using the ArrayResize function, see the section dealing with [dynamic arrays](/en/book/common/arrays/arrays_dynamic)). + +``` +type dynamic1D[]; +type dynamic2D[][size2]; +type dynamic3D[][size2][size3]; +type dynamic4D[][size2][size3][size4]; + +``` + +For fixed-size arrays, initialization is permitted: Initial values are specified for the elements after the equal sign, as a comma-separated list, the entire list being enclosed in braces. For example: + +``` +int array1D[3] = {10, 20, 30}; + +``` + +Here, a 3-sized integer array takes the values of 10, 20, and 30. + +With an initialization list, there is no need to specify the array size in square brackets (for the first dimension). The compiler will assess the size automatically by the list length. For example: + +``` +int array1D[] = {10, 20, 30}; + +``` + +Initial values can be both constants and the constant expressions, i.e., formulas the compiler can compute during compilation. For example, the following array is filled with the number of seconds in a minute, hour, day, and week (representation as formulas is more illustrative than 86400 or 604800): + +``` +int seconds[] = {60, 60 * 60, 60 * 60 * 24, 60 * 60 * 24 * 7}; + +``` + +Such values are usually designed as a preprocessor macro in the code beginning, and then the name of this macro is inserted everywhere where it is necessary in the text. This option is described in the section related to the [Preprocessor](/en/book/basis/preprocessor/preprocessor_define_overview). + +The number of initializing elements may not exceed the array size. Otherwise, the compiler will give the error message, "too many initializers". If the quantity of values is smaller than the array size, the resting elements are initialized by zero. Therefore, there is a brief notation to initialize the entire array by zeros: + +``` +int array2D[2][3] = {0}; + +``` + +Or just empty braces: + +``` +int array2D[2][3] = {}; + +``` + +It works regardless of the number of dimensions. + +To initialize multidimensional arrays, the lists must be nested. For example: + +``` +int array2D[3][2] = {{1, 2}, {3, 4}, {5, 6}}; + +``` + +Here, the first-dimension size of the array is 3; therefore, two commas frame 3 elements inside the external braces. However, since the array is two-dimensional, each of its elements is an array, in turn, the size of each being 2. This is why each element represents a list in braces, each list containing 2 values. + +Supposing, we need a transposed array (the first size is 2, and the second one is 3), then its initialization will change: + +``` +int array2D[2][3] = {{1, 3, 5}, {2, 4, 6}}; + +``` + +We can skip one or more values in the initialization list, if necessary, having marked their places with commas. All skipped elements will also be initialized by zero. + +``` +int array1D[3] = {, , 30}; + +``` + +Here, the first elements will be equal to 0. + +The language syntax permits placing a comma after the last element: + +``` +string messages[] = +{ +  "undefined", +  "success", +  "error", +}; + +``` + +This simplifies adding new elements, especially for multi-string entries. Particularly, if we forget to enter a comma before the newly added element in a string array, the old and the new strings will turn out to be fused within one element (with the same index), while no new element will appear. Moreover, some arrays may be generated automatically (by another program or by macros). Therefore, the unified appearance of all elements is natural. + +"Heap" and "Stack" + +  + + With arrays that can potentially be large, it is important to make the distinction between global and local location in memory. + +  + +Memory for global variables and arrays is distributed within the 'heap', i.e., free memory available to the program. This memory is not practically limited by anything, apart from the physical characteristics of your computer and operating system. The name of 'heap' is explained by the fact that differently sized memory areas are always either allocated or deallocated by the program, which results in the free areas being randomly scattered within the entire bulk. + +  + +Local variables and arrays are located in the stack, i.e., a limited memory area preliminarily allocated for the program, especially for local elements. The name of 'stack' derives from the fact that, during the algorithm execution, the nested calls of functions take place, which accumulate their internal data according to the "piled-up" principle: For instance, OnStart is called by the terminal, a function from your applied code is called from OnStart, then your other function is called from the previous one, etc. At the same time, when entering each function, its local variables are created that continue being there when the nested function is called. It creates local variables, too, which get onto the stack somewhat over the preceding ones. As a result, a stack usually contains some layers of the local data from all functions that had been activated on the path to the current code string. Not until the function being on the top of the stack is completed, its local data will be removed from there. Generally, the stack is a storage that works according to the FILO/LIFO (First In Last Out, Last In First Out) principle. + +  + +Since the stack size is limited, it is recommended to create only local variables in it. However, arrays can be quite large to exhaust the entire stack very soon. At the same time, the program execution is completed with an error. Therefore, we should describe arrays at a global level as static (static) or allocate memory for them dynamically (this is also done from the heap). diff --git a/skills/mql5/references/book/01-basis/0038-basis-arrays-arrays-usage.md b/skills/mql5/references/book/01-basis/0038-basis-arrays-arrays-usage.md new file mode 100644 index 0000000..742f105 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0038-basis-arrays-arrays-usage.md @@ -0,0 +1,112 @@ +# Using arrays + +Values are written to and read from the array elements using a similar syntax and specifying the required indices in square brackets. To put a value into an element, we will use the [assignment operation](/en/book/basis/expressions/operator_assignment) '='. For example, to replace the value of the 0th element of a one-dimensional array: + +``` +array1D[0] = 11; + +``` + +Indexing starts with 0. The index of the last element is equal to the quantity of elements minus 1. Of course, we can use as an index both a constant and any other expression that can be reduced to the integer type (for more details on expressions, see the [following chapter](/en/book/basis/expressions)), such as an integer variable, a function call, or an element of another array with integers (the indirect addressing). + +``` +int index; +// ...  +// index = ... // assign an index somehow +// ... +array1D[index] = 11; + +``` + +For multidimensional arrays, indexes must be specified for all dimensions. + +``` +array2D[index1][index2] = 12; + +``` + +Permitted integer types exclude long and ulong for indices. If we try to use the value of a "long integer" as an index, it will be implicitly converted into int, wherefore the compiler gives the warning "possible loss of data due to type conversion." + +Reading access to the array elements is arranged according to the same principle. For example, this is how an array element can be printed in the log: + +``` +Print(array2D[1][2]); + +``` + +In script GoodTimes, we have already seen the description of the local static array messages with the strings of greetings (inside the Greeting function) and the use of its elements in the return operator. + +``` +string Greeting()  +{ +  static int counter = 0; +  static const string messages[3] = // description +  { +    "Good morning", "Good day", "Good evening" // initialization +  }; +  return messages[counter++ % 3];   // using +} + +``` + +When executing return, we read the element that has the index defined by the expression: counter++ % 3. Division modulo 3 (denoted as '%') ensures that counter increased every time increased by 1 will be forced to the range of the correct values of indices: 0, 1, or 2. If there were not modulo divisions, the index of the requested element would exceed the array size, starting from the 4th call of this function. In such cases, the program execution time error occurs ("array out of range"), and it is unloaded from the chart. + +MQL5 API includes universal functions for many operations with arrays: Allocating memory (for dynamic arrays), filling, copying, sorting, and searching in arrays are all considered in the section [Working with Arrays](/en/book/common/arrays). However, we are presenting one of them now: [ArrayPrint](/en/book/common/arrays/arrays_print) allows the printing of the array elements in the log in a convenient format (considering dimensions). + +Script Arrays.mq5 demonstrates some examples of describing arrays, and the results are printed in the log. We will consider manipulations with the elements of arrays later, upon having studied loops and expressions. + +``` +void OnStart() +{ +  char array[100];      // without initialization +  int array2D[3][2] = +  { +    {1, 2},             // illustrative formatting +    {3, 4}, +    {5, 6} +  }; +  int array2Dt[2][3] = +  { +    {1, 3, 5}, +    {2, 4, 6} +  }; +  ENUM_APPLIED_PRICE prices[] = +  { +    PRICE_OPEN, PRICE_HIGH, PRICE_LOW, PRICE_CLOSE +  }; +  // double d[5] = {1, 2, 3, 4, 5, 6}; // error: too many initializers +  ArrayPrint(array);    // printing random "garbage" values +  ArrayPrint(array2D);  // showing the 2D array in the log +  ArrayPrint(array2Dt); // a "transposed" appearance of the same data 2D +  ArrayPrint(prices);   // getting to know the values of the price enumeration elements +} + +``` + +One of the log entry options is represented below. + +``` +[ 0]   0   0   0   0   0   0   0   0   0   0   0   0 -87 105  82 119   0 +       0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0 +[34]   0   0   0 -32  -3  -1  -1   7   0   0   2   0   0   0   0   0   0 +       0   2   0   0   0   0   0   0   0 -96 104  82 119   0   0   0   0 +[68]   0   0   3   0   0   0   0   0  -1  -1  -1  -1   0   0   0   0 100 +      48   0   0   0   0   0   0   0   0   0   0   0   0   0   0 +    [,0][,1] +[0,]   1   2 +[1,]   3   4 +[2,]   5   6 +    [,0][,1][,2] +[0,]   1   3   5 +[1,]   2   4   6 +2 3 4 1 + +``` + +The array named array does not have any initialization and therefore, memory allocated for it may contain random values. Values will change at each script run. It is recommended to always initialize local arrays, just in case. + +Arrays array2D and array2Dt are printed in the log in an illustrative form, as matrices. It is in no way linked to the fact that we have formatted the initialization lists in the source code in the same manner. + +The prices array has the type of the embedded enumeration ENUM_APPLIED_PRICE. Basically, arrays can be of any type, including structures, function pointers, and other things that we are going to consider. Since enumerations are based on the int type, the values are displayed by digits, not by the names of elements (to obtain the name of a specific element of the enumeration, there is the function [EnumToString](/en/book/common/conversions/conversions_enums), but its mode is not supported in [ArrayPrint](/en/book/common/arrays/arrays_print)). + +The string with the d array description contains an error: Entity of initial values exceeds the array size. diff --git a/skills/mql5/references/book/01-basis/0039-basis-expressions.md b/skills/mql5/references/book/01-basis/0039-basis-expressions.md new file mode 100644 index 0000000..b6dc340 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0039-basis-expressions.md @@ -0,0 +1,16 @@ +# Expressions + +Expressions are essential elements of any programming language. Whatever applied idea underlies an algorithm, it is eventually reduced to data processing, that is, to computations. The expression describes computing some result from one or more predefined values. The values are called operands, while the actions performed with them are denoted by operations or operators. + +As operators that allow manipulating with operands, independent characters or their sequences are used in expressions, such as '+' for addition or '*' for multiplication. They all form several groups, such as arithmetic, bitwise, comparison, logic, and some specialized ones. + +We have already used expressions in the previous sections of this book, such as to initialize variables. In the simplest case, the expression is a constant (literal) that is the only operand, while the computation result is equal to the operand value. However, operands can also be variables, array elements, function call results (for which the function is called directly from the expression), nested expressions, and other entities. + +All operators substitute (return) their result into the parent expression, directly into the place where there were operands, which allows combining them making quite complex hierarchic structures. For example, in the following expression, the result of multiplying variables b by c is added to the value of variable a, and then the value obtained will be stored in variable v: + +``` +v = a + b * c; + +``` + +In this section, we consider the general principles of constructing and computing various expressions, as well as the standard set of operators supported in MQL5 for the built-in types. Later on, in the part dealing with OOP, we will know how operators can be reloaded (redefined) for custom types, i.e., structures and classes, which will allow us to use objects in expressions and perform nonstandard actions with them. diff --git a/skills/mql5/references/book/01-basis/0040-basis-expressions-expressions-overview.md b/skills/mql5/references/book/01-basis/0040-basis-expressions-expressions-overview.md new file mode 100644 index 0000000..9613452 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0040-basis-expressions-expressions-overview.md @@ -0,0 +1,77 @@ +# Basic concepts + +Before proceeding to the specific groups of operators, we should introduce some basic concepts that are inherent in all operators and affect their applicability and behavior in a particular context. + +First of all, by the quantity of operands required, operators can be unary and binary. As is clear from the names, unary ones process one operand, while binary operators process two. In the case of binary, the operator is always placed between operands. Among unary ones, there are operators that must be put before the operand and those to be placed after it. For example, the unary minus ('-') operator allows reversing the sign of the value: + +``` +int x = 10; +int y = -x;  // -10 + +``` + +At the same time, there is a binary operator for subtraction using the same character, '-'. + +``` +int z = x - y; // 10 - -10 -> 20 + +``` + +Choosing a correct operator (action) by the compiler in a specific context is determined by the context of using it in the expression. + +Each operator is assigned priority. It determines the order, in which operators will be computed in complex expressions where there are multiple operators. Higher-priority operators are computed as the first, while the lowest-priority ones as the last. For instance, in the expression 1 + 2 * 3 there are two operations (addition and multiplication) and three operands. Since multiplication has a priority higher than that of addition, the product of 2 * 3 will be found first, and then it will be added to one. + +Later we will provide the full table of operations with priorities. + +Additionally, each operator is characterized by the associativity. It can be left or right and determines the order, in which the successive operators having the same priority are executed. For example, expression 10 - 7 - 1 can purely theoretically be computed in two ways: + +- Subtract 7 from 10 and then subtract 1 from the resulting 3, which gives 2; or +- Subtract 1 from 7, which gives 6, and then subtract 6 from 10, resulting in 4. + +In the first case, computations were performed from left to right, which corresponds with the left associativity; since the subtraction operation is left-associative, indeed, the first answer is correct. + +The second option of computations corresponds with the right associativity and won't be used. + +Let's consider another example where there are priority and associativity involved simultaneously: 11 + 5 * 4 / 2 + 3. Both types of operations, i.e., addition and multiplication, are executed from left to right. If the priorities were not different, we would get 35, although 24 is the correct answer. Changing associativity for the right would give us 14. + +To explicitly redefine priorities in expressions, parentheses can be used, for instance: (11 + 5) * 4 / (2 + 3). What is enclosed in parentheses is computed earlier, and the intermediate result is substituted in the expression to be used in other operations. Groups in parentheses can be nested. For more details, please see section [Grouping with Parentheses](/en/book/basis/expressions/operators_parentheses). + +A right-associative operator can be exemplified by the unary operator of logic negation, '!'. Essentially, its task is to make true from false, and vice versa. Like with other unary operators, associativity means in this context, what side of the operator the operand must be placed. Symbol '!' is placed before the operand, i.e., the operand is to the right. + +``` +int x = 10; +int on_off = !!x;  // 1 + +``` + +In this case, logic negation is performed twice: first time regarding variable x (right '!') and the second time regarding the result of the preceding negation (left '!'). Such double negation allows transforming any nonzero value into 1 due to converting into bool and back. + +The final table of operations will also show associativity. + +Finally, the last but not the least fine point in processing expressions is the order of computing the operands. It should be distinguished from the priority that belongs to the operation, not operands. The order of computing the operands of binary operations is not defined explicitly, which gives the compiler space to optimize the code and enhance its efficiency. The compiler only guarantees that operands will be computed before executing the operation. + +There is a limited set of operations, for which the operand evaluation order is defined. Particularly, for logic AND ('&&') and OR ('||') it is from left to right, and the right part may be omitted if it does not affect anything due to the value of the left part. But as far as the [ternary conditional operator](/en/book/basis/expressions/operator_conditional) '?:' goes, the order is even more intricate, since either one or another branch will be calculated upon computing the first conditions, depending on its trueness. See further sections for more details. + +Operand evaluation order is illustrated by the situation where there are several [function](/en/book/basis/functions) calls in the expression. For instance, let 4 functions be used in the expression: + +``` +a() + b() * c() - d() + +``` + +Priority and associativity rules will only be used for the intermediate results of calling these functions, while the calls themselves can be generated by the compiler in any order it "considers to be necessary" based on the source code features and compiler settings. For example, functions b and c involved in multiplication may be called in the order of [b(), c()] or, vice versa, [c(), b()]. If the functions during being executed may affect the same data, their state will be ambiguous upon the expression computation. + +A similar problem can be seen when working with arrays and increment operators (see [Increment and Decrement](/en/book/basis/expressions/increment_decrement)). + +``` +int i = 0; +int a[5] = {0, 1, 2, 3, 4}; +int w = a[++i] - a[++i]; + +``` + +Depending on whether the left or the right difference operand will be computed as the first, we can get -1 (a[1] - a[2]) or +1 (a[2] - a[1]). Since the MQL5 compiler is ever-improving, there is no guarantee that the current result (-1) will be retained in the future. + +To avoid potential issues, it is recommended not to use an operand repeatedly, if it has already been modified in the same expression. + +In all expressions, there can usually be operands of different types. This leads to the need to cast them to a certain common type, before performing any actions with them. If there are no explicit typecasts, MQL5 performs the implicit conversion where necessary. Besides, conversion rules are different for different type combinations. Explicit and implicit typecasting is discussed in the [relevant section](/en/book/basis/conversion). diff --git a/skills/mql5/references/book/01-basis/0041-basis-expressions-operator-assignment.md b/skills/mql5/references/book/01-basis/0041-basis-expressions-operator-assignment.md new file mode 100644 index 0000000..c489666 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0041-basis-expressions-operator-assignment.md @@ -0,0 +1,88 @@ +# Assignment operation + +Expression calculation results must usually be stored somewhere. The assignment operator denoted by '=' is intended for this purpose in the language. The name of a variable or an array element is placed to the left of it, in which the result must be stored, while the expression (in fact, the formula for computation) is to the right. + +We have already used this operator for the initialization of variables, which is executed only once, during creating them. However, assignment allows changing the values of variables in the course of the algorithm for an arbitrary number of times. For example: + +``` +int z; +int x = 1, y = 2; +z = x; +x = y; +y = z; + +``` + +Variables x and y were initialized by values 1 and 2, whereupon the auxiliary third variable z and three assignments were used to exchange values x and y. + +The assignment operator, like all operators, returns its result into the expression. This enables writing the assignments in a sequence. + +``` +int x, y, z; +x = y = z = 1; + +``` + +Here, 1 will first be assigned to variable z, then to variable y, and finally to variable x. Obviously, this operator is right-associative, because the value being assigned drifts from right to left in the expression. + +We can use the assignment as a part of an expression. But, since its priority is lower than those of all other operators (except for the "comma" one, see [Priorities of Operations](/en/book/basis/expressions/operators_precedence)), it must be enclosed in parentheses (for more details, please see the section on [Grouping with parentheses](/en/book/basis/expressions/operators_parentheses)). This aspect enables situations where mistypes, such as '=' instead of '==', in expressions lead to not executing the statements as intended. See the example of such behavior in the section dealing with [statement ](/en/book/basis/statements/statements_if)[if](/en/book/basis/statements/statements_if). + +The assignment operator imposes certain limitations on what can be to the left of '=' and what to the right of it. In programming, these entities aiming to simplify storing are entitled precisely: LValue and RValue (based on Left and Right). + +LValue and RValue + +  + + LValue represents an entity, for which memory is allocated and, therefore, a value can be written in it. Variable and array elements are the known examples of LValue. Upon having studied OOP, we will get to know another representative of this category: Object, in which the assignment operator can be reloaded. A mandatory element of LValue is the presence of an identifier. + +  + +It should be considered that variables and arrays may be described with the keyword const, and then they cannot act as LValue, because the modification of constants is prohibited. + +  + +RValue is a temporary value used in an expression, such as a literal or value returned due to a function call or due to computing a fragment of the expression. + +  + +Category LValue is of expansive nature, i.e., falling within it allows placing the relevant object to the left of '=' but does not prohibit using it, on par with RValue, to the right of '='. + +  + +Category RValue, over again, is of a limiting nature, i.e., any RValue may only be to the right of '='. + +  + +As a certain LValue element is used to the right of '=', its identifier, in fact, denotes its current contents placed into the expression formula. + +  + +However, if an element of LValue is used to the left of '=', its identifier indicates a memory address (cell) where the new value (expression computation result) should be written. + +  + +Different operators have different limitations regarding whether they can be used for the operands of LValue or RValue. For example, increment '++' and decrement '--' operators (see [Increment and Decrement](/en/book/basis/expressions/increment_decrement)) may only be used with LValue. + +Here are some examples of what is and is not allowed to do with assignment operators (script ExprAssign.mq5): + +``` +// description of variables +const double cx = 123.0; +int x, y, a[5] = {1}; +string s; +// assignment +a[2] = 21;       // ok +x = a[0] + a[1] + a[2]; // ok +s = Symbol();    // ok +cx = 0;          // const variable may not be changed +                 // error: 'cx' - constant cannot be modified +5 = y;           // 5 – this number (literal) +                 // error: '5' - l-value required +x + y = 3;       // to the left of RValue (expression computation result) +                 // error: l-value required +Symbol() = "GBPUSD"; // to the left of RValue with the function call result   +                     // error: l-value required + +``` + +The compiler returns an error of breaking the operator use rules. diff --git a/skills/mql5/references/book/01-basis/0042-basis-expressions-operators-arithmetic.md b/skills/mql5/references/book/01-basis/0042-basis-expressions-operators-arithmetic.md new file mode 100644 index 0000000..1e79e86 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0042-basis-expressions-operators-arithmetic.md @@ -0,0 +1,99 @@ +# Arithmetic operations + +Arithmetic operations include 5 binary ones, i.e., addition, subtraction, multiplication, division, and division modulo, and 2 unary ones, i.e., plus and minus. Symbols used for each of those operations are given in the table below. + +In the column containing examples, e1 and e2 are arbitrary subexpressions. Associativity is marked with 'L' (left to right) and 'R' (right to left). The number in the first column can be considered as precedence of executing the operations. + +| P | Symbols | Description | Example | A | +| --- | --- | --- | --- | --- | +| 2 | + | Unary plus | +e1 | R | +| 2 | - | Unary minus | -e1 | R | +| 3 | * | Multiplication | e1 * e2 | L | +| 3 | / | Division | e1 / e2 | L | +| 3 | % | Division modulo | e1 % e2 | L | +| 4 | + | Addition | e1 + e2 | L | +| 4 | - | Subtraction | e1 - e2 | L | + +Order in the table corresponds with decreasing the priorities: Unary plus and minus are calculated before multiplication and division, while the latter ones, in turn, before addition and subtraction. + +``` +double a = 3 + 4 * 5; // a = 23 + +``` + +In fact, unary plus does not have any effect in calculations, but can be used for a better visualization of the expression. Unary minus reverses the sign of its operand. + +Arithmetic operations are used for numeric types or those that can be cast to them. The calculation result is an RValue. In computation, the storage locations of integer operands are often extended up to the "largest" of the integers used or to int (if all integer types were of a smaller size), as well as cast to a common type. More details can be found in the section on [Typecasting](/en/book/basis/conversion). + +``` +bool b1 = true; +bool b2 = -b1; + +``` + +In this example, variable b1 "expands" to the int type with value 1. Sign reversing gives -1, which in the reverse typecasting to bool gives true (because -1 is not zero). Using logic type in arithmetic computations is not welcome. + +Dividing integers gives an integer, that is, the fractional part, if any, is omitted. It can be checked using the script ExprArithmetic.mq5. + +``` +int a = 24 / 7;      // ok: a = 3 +int b = 24 / 8;      // ok: b = 3 +double c = 24 / 7;   // ok: c = 3 (!) + +``` + +Although variable c is described as double, there are integers in the expression to initialize it; therefore, the division performed is an integer. To perform a division with a fractional part, at least one operand must be of real type (the second one will also be cast to it). + +``` +double d = 24.0 / 7; // ok: d = 3.4285714285714284 + +``` + +Operator '%' calculates the remainder of integer division (it is only applicable to two operands of integer type). + +``` +int x = 11 % 5;   // ok: x = 1 +int y = 11 % 5.0; // no real number can be used +                  // error: '%' - illegal operation use + +``` + +Where operands have different signs, operators '*' and '/' give a negative number. The following rules apply to operator '%': + +- if the divisor of operator '%' is negative, the sign "escapes"; and +- if the dividend of operator '%' is negative, the result is negative; + +This is easy to check using the alternative calculation of division modulo: m % n = m - m / n * n. It should be kept in mind that division m / n for integers will be rounded; therefore, m / n * n is not equal to m, in the general case. + +In section [Characteristics of Arrays](/en/book/basis/arrays/arrays_overview), we delved into the idea that a multidimensional array could be represented by a one-dimensional one due to recalculating the indices of their elements. We also provided the formula to obtain an index through in a one-dimensional array by the coordinates (column number X and row number Y at the string length of N) of the two-dimensional array. + +``` +index = Y * N + X + +``` + +Operation '%' allows us to perform a more convenient backward calculation, i.e., find X and Y by the index-through: + +``` +Y = index / N +X = index % N + +``` + +If an unpresentable result NaN (Not A Number, such as infinity, square root of a negative number, etc.) was obtained at some stage during calculating the expression, all subsequent operations with it will also produce a NaN. It can be distinguished from a normal number using the MathIsValidNumber function (see [Mathematical Functions](/en/book/common/maths)). + +``` +double z = DBL_MAX / DBL_MIN - 1; // inf: Not A Number + +``` + +Here, it is subtracted from the NaN (obtained from division) and gives the NaN again. + +Addition operation is defined for strings and performs the concatenation, i.e., combining them. + +``` +string s = "Hello, " + "world!"; // "Hello, World!" + +``` + +Other operations are prohibited for strings. diff --git a/skills/mql5/references/book/01-basis/0043-basis-expressions-increment-decrement.md b/skills/mql5/references/book/01-basis/0043-basis-expressions-increment-decrement.md new file mode 100644 index 0000000..dad5317 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0043-basis-expressions-increment-decrement.md @@ -0,0 +1,47 @@ +# Increment and decrement + +Increment and decrement operators allow writing the increase or decrease of an operand by 1 in a simplified manner. They most frequently occur inside [loops](/en/book/basis/statements/statements_for) to modify indexes when accessing to arrays or other objects supporting enumeration. + +The increment is denoted by two consecutive pluses: '++'. Decrement is denoted by two consecutive minuses: '--'. + +There are two types of such operators: Prefix and postfix. + +Prefix operators, as the name implies, are written before operand (++x, --x). They change the operand value, and this new value is involved in the further calculations of the expression. + +Postfix operators are written after operand (x++, x--). They substitute the copy of the current operand value in the expression and then change its value (the new value does not get into the expression). Simple examples are given in the script ExprIncDec.mq5. + +``` +int i = 0, j; +j = ++i;       // j = 1, i = 1 +j = i++;       // j = 1, i = 2 + +``` + +Postfix form may be useful for more compact writing of expressions combining a reference to the preceding value of the operand and its side modification (two separate statements would be required to make an alternative record of the same). In all other cases, it is recommended to use the prefix form (it does not create a temporary copy of the "old" value). + +In the following example, the sign is reversed in the array elements consecutively, until the zeroth element is found. Moving through the array indices is ensured by postfix increment k++ inside [the loop ](/en/book/basis/statements/statements_while)[while](/en/book/basis/statements/statements_while). Due to postfix, expression a[k++] = -a[k] first updates the kth element and then increases k by 1. Then the assignment result is checked for not being equal to zero (!= 0, see [the following section](/en/book/basis/expressions/operators_relational)). + +``` +int k = 0; +int a[] = {1, 2, 3, 0, 5}; +while((a[k++] = -a[k]) != 0){} +// a[] = {-1, -2, -3, 0, 5}; + +``` + +The table below shows the increment and decrement operators in order of priority: + +| P | Symbols | Description | Example | A | +| --- | --- | --- | --- | --- | +| 1 | ++ | Postfix increment | e1++ | L | +| 1 | -- | Postfix decrement | e1-- | L | +| 2 | ++ | Prefix increment | ++e1 | R | +| 2 | -- | Prefix decrement | --e1 | R | + +All increment and decrement operations have a priority higher than arithmetic operations. Prefixes are of a lower priority than postfixes. In the following example, the "old" value of x is summed up with the value of y, upon which x is incremented. If the prefix priority were higher, the increment of y would be performed, upon which the new value, 6, would be summed up with x, and we would get z = 6, x = 0 (previous). + +``` +int x = 0, y = 5; +int z = x+++y; // "x++ + y" : z = 5, x = 1 + +``` diff --git a/skills/mql5/references/book/01-basis/0044-basis-expressions-operators-relational.md b/skills/mql5/references/book/01-basis/0044-basis-expressions-operators-relational.md new file mode 100644 index 0000000..7bcdd4b --- /dev/null +++ b/skills/mql5/references/book/01-basis/0044-basis-expressions-operators-relational.md @@ -0,0 +1,87 @@ +# Comparison operations + +As the name implies, these operations are intended for comparing two operands and returning a logic feature, true or false, depending on the condition to hold in the comparison. + +The table below gives all comparison operations and their properties, such as symbols used, priorities, examples, and associativity. + +| P | Symbols | Description | Example | A | +| --- | --- | --- | --- | --- | +| 6 | < | Less | e1 < e2 | L | +| 6 | > | Greater | e1 > e2 | L | +| 6 | <= | Less than or equal | e1 <= e2 | L | +| 6 | >= | greater than or equal | e1 >= e2 | L | +| 7 | == | Equal | e1 == e2 | L | +| 7 | != | Not equal | e1 != e2 | L | + +The principle of each operation is to compare two operands using the criterion from the column containing its description. For example, entry "x < y" means checking whether "x is lesser than y". Correspondingly, the comparison result will be true if x is really lesser than y, and false in all other cases. + +Comparisons work for the operands of any type (for different types, [typecasting](/en/book/basis/conversion/conversion_implicit) is performed). + +Considering the left associativity and the return of the bool type result, constructing a sequence of comparisons does not work so obviously. For example, a hypothetic expression to check whether the value y lies between the values of x and z, could seemingly appear as follows: + +``` +int x = 10, y = 5, z = 2; +bool range = x < y < z;   // true (!) + +``` + +However, such an expression is processed in a different manner. Even the compiler distinguishes it by the warning: "unsafe use of type 'bool' in operation". + +Due to the left associativity, the left condition x < y is checked first, and its result is substituted as a temporary value of the bool type into the expression that goes as follows: b < z. Then the value of z is compared to true or false in the temporary variable b. To check whether y ranges between x and z, you should use two comparison operations combined with the logic operation AND (it will be considered in the [next section](/en/book/basis/expressions/operators_logical)). + +``` +int x = 10, y = 5, z = 2; +bool range = x < y && y < z;   // false + +``` + +When using the comparing for equality/inequality, the features of the operand types shall be considered. For instance, floating-point numbers often contain "approximate" values after calculations (we considered the accuracy of representing double and float in the section [Real Numbers](/en/book/basis/builtin_types/float_numbers)). For example, the sum of 0.6 and 0.3 is not strictly 0.9: + +``` +double p = 0.3, q = 0.6; +bool eq = p + q == 0.9;        // false +double diff = p + q - 0.9;     // -0.000000000000000111 + +``` + +The difference makes 1*10-16, but it is sufficient for the comparison operation to return false. + +Therefore, real numbers should be compared for equality/inequality using the greater-/less-then operators for their difference and acceptable deviation that is sorted out manually, based on the features of the computation, or a universal one is taken. Recall that for double and float, the embedded accuracy constants, DBL_EPSILON and FLT_EPSILON, are defined, valid for the value of 1.0. They must be scaled to compare other values. In script ExprRelational.mq5, one of the possible realizations of function isEqual is presented to compare real numbers, which considers this aspect. + +``` +bool isEqual(const double x, const double y) +{ +   const double diff = MathAbs(x - y); +   const double eps = MathMax(MathAbs(x), MathAbs(y)) * DBL_EPSILON; +   return diff < eps; +} + +``` + +Here we use the function of obtaining an absolute unsigned value (MathAbs) and the highest of the two values (MathMax). They will be described in the section [Mathematical Functions](/en/book/common/maths) of Part 4. The absolute difference between the parameters of function isEqual is compared to the calibrated tolerance in variable eps using operation '<'. + +This function cannot be used to compare with absolute zero, anyway. For this purpose, you can use the following approach (it will probably require some adaptation to your specific needs): + +``` +bool isZero(const double x) +{ +   return MathAbs(x) < DBL_EPSILON; +} + +``` + +Strings are compared lexicographically, i.e., letter by letter. The code of each character is compared to the code of the character in the same position of the second string. Comparison is performed until a difference in the codes is found or one of the strings ends. The string ratio will be equal to that of the first differing characters, or a longer string will be considered greater than the shorter one. Remember that upper- and lowercase letters have different codes, and strange enough, uppercase ones have smaller codes than the lowercase ones. + +An empty string "" (in fact, it stores one terminal 0) is not equal to the special value of NULL which means no string. + +``` +bool cmp1 = "abcdef" > "abs";     // false, [2]: 's' > 'c' +bool cmp2 = "abcdef" > "abc";     // true,  by length +bool cmp3 = "ABCdef" > "abcdef";  // false, by case +bool cmp4 = "" == NULL;           // false + +``` + +Moreover, to compare strings, MQL5 provides some functions that will be described in the section [Working with Strings](/en/book/common/strings). + +In comparing for equality/inequality, it is not recommended to use bool constants: true or false. The matter is that, in expressions like v == true or v == false, operand v can be interpreted intuitively as a logical type, while in fact, it is a number. As it is known, zero value is considered false in numbers, while all others are interpreted as true (we often want to use it as an indication of some result being present or absent). However, in this case, typecasting goes backward: true or false are "expanded" to a numeric type v and actually become equal to 1 and 0, respectively. Such a comparison will have a result other than the expected one (for example, comparison 100 == true will turn out to be false). diff --git a/skills/mql5/references/book/01-basis/0045-basis-expressions-operators-logical.md b/skills/mql5/references/book/01-basis/0045-basis-expressions-operators-logical.md new file mode 100644 index 0000000..601193e --- /dev/null +++ b/skills/mql5/references/book/01-basis/0045-basis-expressions-operators-logical.md @@ -0,0 +1,59 @@ +# Logical operations + +Logical operations perform computations on logical operands and return a result of the same type. + +| P | Symbols | Description | Example | A | +| --- | --- | --- | --- | --- | +| 2 | ! | Logical NOT | !e1 | R | +| 11 | && | Logical AND | e1 && e2 | L | +| 12 | || | Logical OR | e1 || e2 | L | + +Logical NOT transforms true into false and false into true. + +Logical AND is equal to true if both operands are equal to true. + +Logical OR is equal to true if at least one operand is equal to true. + +Operators AND and OR always compute operands from left to right and, if possible, use the computational shortcut. If the left operand is equal to false, then operator AND skips the second operand, because it does not affect anything – the result is already false. If the left operand is equal to true, then operator OR skips the second operand for the same reason, since the result will, in any case, be equal to true. + +This is often used in programs to prevent from errors in the second (and subsequent) operands. For example, we can hedge ourselves against the error of accessing a non-existing array element: + +``` +index < ArraySize(array) && array[index] != 0 + +``` + +Here we use the built-in function ArraySize that returns the array length. Only if index is smaller than the length, the element with this index is read and compared with zero. + +Checking by contraries, using '||' is also used, for example: + +``` +ArraySize(array) == 0 || array[0] == 0 + +``` + +The condition is true immediately if the array is null. And only if there are elements, the additional check for the contents will continue. + +If the expression consists of multiple operands combined by logical OR, then with the first true (if any) the total result of true will be obtained immediately. However, if operands are combined by logical AND, then with the first false the total result of false will be obtained immediately. + +Of course, you can combine different operations within one expression, considering their different priority: Negation is executed first, then the AND-related conditions, and in the end the OR-related conditions. If another sequence is required, it must be explicitly specified using parentheses. + +For example, the following expression without parentheses, A && B || C && D, is in fact equivalent to: (A && B) || (C && D). For the logical OR to be executed as the first, it should be enclosed in parentheses: A && (B || C) && D. For more details on using parentheses, see section [Grouping with Parentheses](/en/book/basis/expressions/operators_parentheses). + +Simple examples are given in script ExprLogical.mq5 to check logical operations in practice. + +``` +int x = 3, y = 4, z = 5; +bool expr1 = x == y && z > 0;  // false, x != y, z does not matter +bool expr2 = x != y && z > 0;  // true,  both conditions are complied with +bool expr3 = x == y || z > 0;  // true,  it is sufficient that z > 0 +bool expr4 = !x;               // false, x must be 0 to get true +bool expr5 = x > 0 && y > 0 && z > 0; // true, all 3 are complied with +bool expr6 = x < 0 || y > 0 && z > 0; // true, y and z are sufficient +bool expr7 = x < 0 || y < 0 || z > 0; // true, z is sufficient + +``` + +In the string of calculating expr6, the compiler gives the warning: "Check operator precedence for possible error; use parentheses to clarify precedence". + +Logical operations '&&' and '||' should not be mixed with bitwise operations '&' and '|' (considered in the [next section](/en/book/basis/expressions/operators_bitwise)). diff --git a/skills/mql5/references/book/01-basis/0046-basis-expressions-operators-bitwise.md b/skills/mql5/references/book/01-basis/0046-basis-expressions-operators-bitwise.md new file mode 100644 index 0000000..e845eff --- /dev/null +++ b/skills/mql5/references/book/01-basis/0046-basis-expressions-operators-bitwise.md @@ -0,0 +1,70 @@ +# Bitwise operations + +Sometimes you may need to process numbers at the bit level. For this purpose, there is a group of bitwise operations applicable to integer types. + +All symbols and descriptions of bitwise operators are provided with their associativity and in order of their priority in the table below. + +| P | Symbols | Description | Example | A | +| --- | --- | --- | --- | --- | +| 2 | ~ | Bitwise complement (inversion) | ~e1 | R | +| 5 | << | Shift to the left | e1 << e2 | L | +| 5 | >> | Shift to the right | e1 >> e2 | L | +| 8 | & | Bitwise AND | e1 & e2 | L | +| 9 | ^ | Bitwise exclusive OR | e1 ^ e2 | L | +| 10 | | | Bitwise OR | e1 | e2 | L | + +Of the entire group, only the bitwise complement operation '~' is unary, while all others are binary. + +In all cases, if the operand size is less than int/uint, it is preliminarily extended to int/uint by adding 0 bits into higher order. Based on the operand type being signed/unsigned, a high-order bit may affect the sign. + +Standard Windows application, Calculator, may help understand the representation of numbers at the bit level. If you select the Programmer operation mode in the View menu, the groups of toggle buttons will appear in the program to select representing the number in a hexadecimal (Hex), decimal (Dec), octal (Oct), or binary (Bin) form. It is the latter one that shows bits. Moreover, you can select the number size: 1, 2, 4, and 8 bytes. The buttons allow executing all the operations considered: Not ('~'), And ('&'), Or ('|'), Xor ('^'), Lsh ('<<'), and Rsh ('>>'). + +  + +Since the Calculator uses signed numbers, negative values may appear when toggling to the decimal mode (remember that the high-order bit is interpreted as a sign). For convenient analysis, it is reasonable to exclude the minus that appears, for which purpose it is necessary to select the size in bytes one grade higher. For example, to check the values within the range up to 255 (uchar, unsigned one-byte integer), you should select 2 bytes (otherwise, only decimal values through 127 will be positive, while the others will be displayed in the negative region). + +Bitwise complement creates a value, in which the 0-bit is in the place of all 1-bits, while 1-bit is in the place of 0-bits. For example, the negation of a byte with all zero bits gives a byte with all 1 bits. Number 50 appears in the bitwise format as '00110010' (byte). Its inversion gives '11001101'. + +Unity represented hexadecimally is 0x0001 (for short). Inversion of these bits gives 0xFFFE (see script ExprBitwise.mq5). + +``` +short v = ~1;  // 0xfffe = -2 +ushort w = ~1; // 0xfffe = 65534 + +``` + +Bitwise AND checks each bit in both operands and in the positions where two set bits (1) are found, stores the 1-bit into the result. In all other cases (where there is only a set bit in one operand or they are reset in both places), the 0-bit is written in the result. + +Bitwise OR writes 1-bits into the result if they are on the positions where there is a set bit in at least one of two operands. + +Bitwise exclusive OR writes in the result the 1-bits on the positions where there is a set bit in either the first or second operand, but not in both at the same time. The binary representation of two numbers, X and Y, and the results of bitwise operations with them are shown below. + +``` +X       10011010   154 +Y       00110111    55 +  +X & Y   00010010    18 +X | Y   10111111   191 +X ^ Y   10101101   173 + +``` + +When writing complex expressions from several different operators, use grouping with parentheses in order not to become confused with priorities. + +Shift operations move bits to the left ('<<') or right ('>>') by the quantity of bits, defined in the second operand that must be a non-negative integer. As a result, left (for '<<') or right (for '>>') bits are dropped, since they go beyond the memory cell boundaries. With the left shift, the relevant number of 0 bits are added on the right. With the right shift, either 0 bits are added on the left (if the operand is unsigned) or the sign bit is reproduced (if the operand is signed). In the latter case, 0 bits are added on the left for positive numbers and 1 bits for negative ones; i.e., the sign retains. + +``` +short q = v << 5;  // 0xffc0 = -64 +ushort p = w << 5; // 0xffc0 = 65472 +short r = q >> 5;  // 0xfffe = -2 +ushort s = p >> 5; // 0x07fe = 2046 + +``` + +In the example above, the initial left shift "destroyed" the high-order bits of variable p, while the subsequent right shift by the same quantity of bits filled them with zeros, which led to decreasing the value from 0xffc0 to 0x07fe. + +Shift size (quantity of bits) must be less than that of the operand type (considering its potential extension). Otherwise, all initial bits will get lost. + +Shifting by 0 bits leaves the number unchanged. + +Bitwise operations '&' and '|' should not be mixed with logical operations '&&' and '||' (considered in the [preceding section](/en/book/basis/expressions/operators_logical)). diff --git a/skills/mql5/references/book/01-basis/0047-basis-expressions-operators-compound.md b/skills/mql5/references/book/01-basis/0047-basis-expressions-operators-compound.md new file mode 100644 index 0000000..4a96412 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0047-basis-expressions-operators-compound.md @@ -0,0 +1,55 @@ +# Modification operations + +Modification that is also called compound assignment allows combining within one operator [arithmetic](/en/book/basis/expressions/operators_arithmetic) or [bitwise](/en/book/basis/expressions/operators_bitwise) operations with normal [assignment](/en/book/basis/expressions/operator_assignment). + +| P | Symbols | Description | Example | A | +| --- | --- | --- | --- | --- | +| 14 | += | Addition with assignment | e1 += e2 | R | +| 14 | -= | Subtraction with assignment | e1 -= e2 | R | +| 14 | *= | Multiplication with assignment | e1 *= e2 | R | +| 14 | /= | Division with assignment | e1 /= e2 | R | +| 14 | %= | Division modulo with assignment | e1 %= e2 | R | +| 14 | <<= | Left shift with assignment | e1 <<= e2 | R | +| 14 | >>= | Right shift with assignment | e1 >>= e2 | R | +| 14 | &= | Bitwise AND with assignment | e1 &= e2 | R | +| 14 | |= | Bitwise OR with assignment | e1 |= e2 | R | +| 14 | ^= | Bitwise AND/OR with assignment | e1 ^= e2 | R | + +These operators execute the relevant action for operands e1 and e2, whereupon the result is stored in e1. + +An expression like e1 @= e2 where @ is any operator from the table is approximately equivalent to e1 = e1 @ e2. The word "approximately" emphasizes the presence of some subtle aspects. + +First, if the place of e2 is occupied by an expression with an operator having a lower priority than that of @, e2 is still calculated before that. That is, if the priority is marked with parentheses, we will get e1 = e1 @ (e2). + +Second, if there are side modifications of variables in expression e1, they are made only once. The following example demonstrates this. + +``` +int a[] = {1, 2, 3, 4, 5}; +int b[] = {1, 2, 3, 4, 5}; +int i = 0, j = 0; +a[++i] *= i + 1;           // a = {1, 4, 3, 4, 5}, i = 1 +                           // not equivalent! +b[++j] = b[++j] * (j + 1); // b = {1, 2, 4, 4, 5}, j = 2 + +``` + +Here, arrays a and b contain identical elements and are processed using index variables i and j. At the same time, the expression for array a uses operation '*=', while that for array b uses the equivalent. Results are not equal: Both index variables and arrays differ. + +Other operators will be useful in problems with bit-level manipulations. Thus, the following expression can be used to set a specific bit into 1: + +``` +ushort x = 0; +x |= 1 << 10; + +``` + +Here, shift 1 ('0000 0000 0000 0001') is made by 10 bits to the left, which results in obtaining a number with one set 10th bit ('0000 0100 0000 0000'). Bitwise OR operation copies this bit into variable x. + +To reset the same bit, we will write: + +``` +x &= ~(1 << 10); + +``` + +Here, the inversion operation is applied to 1 shifted by 10 bits to the left (which we saw in the preceding expression), which results in all bits changing their value: '1111 1011 1111 1111'. Bitwise AND operation resets the zeroed bits (in this case, one) in variable x, while all other bits in x remain unchanged. diff --git a/skills/mql5/references/book/01-basis/0048-basis-expressions-operator-conditional.md b/skills/mql5/references/book/01-basis/0048-basis-expressions-operator-conditional.md new file mode 100644 index 0000000..e3f5c6a --- /dev/null +++ b/skills/mql5/references/book/01-basis/0048-basis-expressions-operator-conditional.md @@ -0,0 +1,97 @@ +# Conditional ternary operator + +Conditional ternary operator allows describing in a single expression two calculation options, based on a certain condition. The operator syntax is as follows: + +``` +condition ? expression_true : expression_false + +``` + +The logical condition must be specified in the first operand 'condition'. This can be an arbitrary combination of [comparison operations](/en/book/basis/expressions/operators_relational) and [logical operations](/en/book/basis/expressions/operators_logical). Both branches must be present. + +If the condition is true, expression expression_true will be computed, while if it is false, the expression_false will be computed. + +This operator guarantees that only one of the expressions expression_true and expression_false will be executed. + +Types of the two expressions must be identical, otherwise, there will be an attempt to [implicitly typecast](/en/book/basis/conversion/conversion_implicit) them. + +Please note that the result of processing expressions in MQL5 always represents an RValue (in C++, if only LValues are in expressions, then the result of the operator will also be LValue). Thus, the following code is compiled well in C++, but gives an error in MQL5: + +``` +int x1, y1; ++(x1 > y1 ? x1 : y1); // '++' - l-value required + +``` + +Conditional operators can be nested, that is, it is permitted to use another conditional operator as a condition or either branch (expression_true or expression_false). At the same time, it cannot be always clear what the conditions relate to (if parentheses are not used to explicitly denote grouping). Let's consider examples from ExprConditional.mq5. + +``` +int x = 1, y = 2, z = 3, p = 4, q = 5, f = 6, h = 7; +int r0 = x > y ? z : p != 0 && q != 0 ? f / (p + q) : h; // 0 = f / (p + q) + +``` + +In this case, the first logical condition represents comparison x > y. If it is true, the branch with variable z is executed. If it is false, the additional logical condition p != 0 && q != 0 is checked, with two expression options, as well. + +Below are some more operators, in which logical conditions are written uppercase, while computation options are lowercase. For simplicity, they all are made variables (from the example above). In reality, each of the three components may be a richer expression. + +For each string, you can track how the result is obtained, which has been shown in the comment. + +``` +bool A = false, B = false, C = true; +int r1 = A ? x : C ? p : q;                              // 4 +int r2 = A ? B ? x : y : z;                              // 3 +int r3 = A ? B ? C ? p : q : y : z;                      // 3 +int r4 = A ? B ? x : y : C ? p : q;                      // 4 +int r5 = A ? f : h ? B ? x : y : C ? p : q;              // 2 + +``` + +Since the operator is right-associative, the compound expression is analyzed from right to left, that is, the rightmost structure with three operands combined by '?' and ':' becomes the operand of the external condition written to the left. Then, considering this substitution, the expression is analyzed from right to left again, and so on, until the final complete upper-level structure '?:' is obtained. + +Therefore, the expressions above are grouped as follows (parentheses denote the implicit interpretation of the compiler; but such parentheses could be added into expressions to visualize the source code, which approach is actually recommended). + +``` +int r0 = x > y ? z : ((p != 0 && q != 0) ? f / (p + q) : h); +int r1 = A ? x : (C ? p : q);  +int r2 = A ? (B ? x : y) : z;  +int r3 = A ? (B ? (C ? p : q) : y) : z;  +int r4 = A ? (B ? x : y) : (C ? p : q);  +int r5 = (A ? f : h) ? (B ? x : y) : (C ? p : q);  + +``` + +For variable r5, the first condition A ? f : h computes the logical condition for the subsequent expression and therefore, is transformed into bool. Since A is equal to false, the value is taken from variable h. It is not equal to 0; therefore, the first condition is considered true. This results in the actuating branch (B ? x : y), from which the value of variable y is returned, since B is equal to false. + +There must be all 3 components (a condition and 2 alternatives) in the operator. Otherwise, the compiler will generate the error "unexpected token": + +``` +// ';' - unexpected token +// ';' - ':' colon sign expected +int r6 = A ? B ? x : y; // lack of alternative + +``` + +In the compiler language, a token is an indivisible fragment of the source code, having its independent meaning or purpose, such as type, identifier, punctuation character, etc. The entire source code is divided by the compiler into a sequence of tokens. Signs of the operators considered are tokens, too. In the code above, there are two symbols '?', and there must be two symbols ':' matching with them, but it is the only one. Therefore, the compiler "says" that the statement end symbol ';' is premature and "inquires" what exactly is deficient: "colon sign expected". + +Since the conditional operator has a very low priority (13 in the full table, see [Priorities of Operations](/en/book/basis/expressions/operators_precedence)), it is recommended to enclose it in parentheses. This makes it easier to avoid situations where the operands of a conditional operator could be "caught" by the neighboring operations having higher priorities. Fir instance, if we need to calculate the value of a certain variable w via the sum of two ternary operators, a straightforward approach might appear as follows: + +``` +int w = A ? f : h + B ? x : y;                           // 1 + +``` + +This will work differently than we thought. Due to the higher priority, the sum h + B is considered as a single expression. Considering its parsing from right to left, this sum appears as a condition and is cast to the bool type, which is even warned by the compiler as "expression not boolean". Compiler interpretation can even be visualized by parentheses: + +``` +int w = A ? f : ((h + B) ? x : y);                       // 1 + +``` + +To solve the problem, we should place parentheses in our own way. + +``` +int v = (A ? f : h) + (B ? x : y);                       // 9 + +``` + +Deep nesting of conditional operators impacts adversely on the code understandability. Nesting levels exceeding two or three should be avoided. diff --git a/skills/mql5/references/book/01-basis/0049-basis-expressions-operator-comma.md b/skills/mql5/references/book/01-basis/0049-basis-expressions-operator-comma.md new file mode 100644 index 0000000..d875b50 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0049-basis-expressions-operator-comma.md @@ -0,0 +1,27 @@ +# Comma + +Operator comma that is explicitly denoted as ',' is placed between two expressions computed independently from left to right. In other words, this operator does not perform any actions itself but just allows specifying the sequence of two or more expressions within a statement. + +Expressions placed right-hand in the sequence can use the results of computing the left-hand expressions, since they have already been processed. + +The operator result is the result of the rightmost expression. The operator has the lowest priority. + +Currently, using the operator in MQL5 is limited by the header of the [for statement](/en/book/basis/statements/statements_for). + +Example: + +``` +for(i=0,j=99; i<100; i++,j--)  +   Print(array[i][j]); + +``` + +Let's repeat the key aspects of the comma operator in MQL5: + +Order of evaluation: + +- Expressions are processed from left to right. Thus, the expressions on the right can use the results of the expressions on the left since they have already been processed. + +Result and priority: + +- The result of the comma operator is the value of the rightmost expression. It's important to note that the comma operator has the lowest priority, meaning that other operators in the expression may have higher priorities. diff --git a/skills/mql5/references/book/01-basis/0050-basis-expressions-operators-sizeof-typename.md b/skills/mql5/references/book/01-basis/0050-basis-expressions-operators-sizeof-typename.md new file mode 100644 index 0000000..466b0be --- /dev/null +++ b/skills/mql5/references/book/01-basis/0050-basis-expressions-operators-sizeof-typename.md @@ -0,0 +1,51 @@ +# Special operators sizeof and typename + +sizeof + +The sizeof operator returns the size of its operand in bytes. Operator syntax: sizeof(x), where x can be a type or an expression. The expression is not computed in this case, since operator sizeof is executed at the compilation stage and, in fact, a constant is substituted in its place in the expression. + +For fixed-size arrays, the operator returns the total amount of the allocated memory, that is, the multiplication of the number of elements in all dimensions by the type size in bytes. For dynamic arrays, it returns the size of an internal structure storing the array properties. + +Let's give some examples with explanations (ExprSpecial.mq5). + +``` +double array[2][2]; +double dynamic1[][1]; +double dynamic2[][2]; +Print(sizeof(double));                           // 8 +Print(sizeof(string));                           // 12 +Print(sizeof("This string is 29 bytes long!"));  // 12 +Print(sizeof(array));                            // 32 +Print(sizeof(array) / sizeof(double));           // 4 (quantity of elements) +Print(sizeof(dynamic1));                         // 52 +Print(sizeof(dynamic2));                         // 52 + +``` + +The result to be printed in the log is marked in the comments. + +Type double takes up 8 bytes. The size of the string type is 12. These 12 bytes store the service information we mentioned in the section dealing with type [string](/en/book/basis/builtin_types/strings). This memory is allocated for any string (even uninitialized). Please note that a string containing a 29-character text is also sized 12. This is because both an empty string and a string with some contents have an internal structure intended for storing a reference to memory. To obtain the text length, we should use the [StringLen](/en/book/common/strings/strings_init) function. + +Fixed-size array size is really computed as the multiplication of the number of elements (2*2=4) by the double type size (8), a total of 32. As a consequence, an expression like sizeof(array) / sizeof(double) allows finding out the entity of elements in it. + +For dynamic arrays, the internal structure size is 52 bytes. Differences in the descriptions of arrays dynamic1 and dynamic2 do not affect this value. + +Operator sizeof is especially useful to get the sizes of [classes](/en/book/oop/classes_and_interfaces) and [structures](/en/book/oop/structs_and_unions). + +typename + +Operator typename returns a string with the name of the parameter passed to it, which can be a type or an expression. For arrays, along with the data type keyword, a tag is printed as a pair of parentheses (or several ones, depending on the array dimensionality). + +``` +Print(typename(double));                         // double +Print(typename(array));                          // double [2][2] +Print(typename(dynamic1));                       // double [][1] +Print(typename(1 + 2));                          // int + +``` + +For custom types, such as classes, structures, and others (that we will consider in Part 3), the type name follows the entity category, such as "class MyCustomType". Moreover, for constants, the "const" modifier will be added to the string description. + +Therefore, to know the short type name consisting of one word, use macro TYPENAME from the attached file TypeName.mqh. + +It can be necessary to learn the type name in the so-called [templates](/en/book/oop/templates) that can generate from the source code similar realizations for different types defined in the parameters of templates. diff --git a/skills/mql5/references/book/01-basis/0051-basis-expressions-operators-parentheses.md b/skills/mql5/references/book/01-basis/0051-basis-expressions-operators-parentheses.md new file mode 100644 index 0000000..1b37e4a --- /dev/null +++ b/skills/mql5/references/book/01-basis/0051-basis-expressions-operators-parentheses.md @@ -0,0 +1,20 @@ +# Grouping with parentheses + +In the preceding sections, we have already seen more than a few times that some expressions can cause unexpected results due to the priorities of operations. To explicitly change the computation order, we should use parentheses. Part of the expression enclosed in them gets a higher priority as compared to the environment, without regard to default priorities. Pairs of parentheses can be nested, but it is not recommended to make more than 3-4 nesting levels. It is better to divide the too complex expressions into several simpler ones. + +Script ExprParentheses.mq5 shows the evolution of placing parentheses within one expression. The initial intent for it is to set the bit in variable flags using the left-shift operation '<<'. The bit number is taken from variable offset if it is not zero, or otherwise, as 1 (remember that numbering starts with zero). Then the obtained value is multiplied by coefficient. No need to search for any applied sense in this example. However, more sophisticated structures can occur, too. + +``` +int offset = 8; +int coefficient = 10, flags = 0; +int result1 = coefficient * flags | 1 << offset > 0 ? offset : 1;     // 8 +int result2 = coefficient * flags | 1 << (offset > 0 ? offset : 1);   // 256 +int result3 = coefficient * (flags | 1 << (offset > 0 ? offset : 1)); // 2560 + +``` + +The first version, without parentheses, seems suspicious even to the compiler. It gives a warning that we have already known: "expression not boolean". The matter is that the ternary conditional operator has the lowest priority of all operators here. For this reason, the entire left part before '?' is considered its condition. Inside the condition, calculations are in the following order: Multiplication, bitwise shift, "more than" comparison, and bitwise OR, which results in an integer. Of course, it can be used as true or false, but it is desired to "communicate" such intentions to the compiler using [explicit typecasting](/en/book/basis/conversion/conversion_explicit). If it is absent, the compiler considers the expression suspicious, and not in vain. The first calculation results in 8. It is incorrect. + +Let's add parentheses around the ternary operator. The warning of the compiler will disappear. However, the expression is still computed wrongly. Since the priority of multiplication is higher than that of bitwise OR, variables coefficient and flags are multiplied before the bit mask is used, which is obtained by shifting to the left. The result is 256. + +Finally, having added another pair of parentheses, we will get the correct result: 2560. diff --git a/skills/mql5/references/book/01-basis/0052-basis-expressions-operators-precedence.md b/skills/mql5/references/book/01-basis/0052-basis-expressions-operators-precedence.md new file mode 100644 index 0000000..8366e91 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0052-basis-expressions-operators-precedence.md @@ -0,0 +1,61 @@ +# Priorities of operations + +Here is the full table of all operations in the order of their priorities. + +| P | Symbols | Description | Example | A | +| --- | --- | --- | --- | --- | +| 0 | :: | Scope resolution | n1 :: n2 | L | +| 1 | () | Grouping | (e1) | L | +| 1 | [] | Index | [e1] | L | +| 1 | . | Dereferencing | n1.n2 | L | +| 1 | ++ | Postfix increment | e1++ | L | +| 1 | -- | Postfix decrement | e1-- | L | +| 2 | ! | Logical NOT | !e1 | R | +| 2 | ~ | Bitwise complement (inversion) | ~e1 | R | +| 2 | + | Unary plus | +e1 | R | +| 2 | - | Unary minus | -e1 | R | +| 2 | ++ | Prefix increment | ++e1 | R | +| 2 | -- | Prefix decrement | --e1 | R | +| 2 | (type) | Typecasting | (n1) | R | +| 2 | & | Taking the address | &n1 | R | +| 3 | * | Multiplication | e1 * e2 | L | +| 3 | / | Division | e1 / e2 | L | +| 3 | % | Division modulo | e1 % e2 | L | +| 4 | + | Addition | e1 + e2 | L | +| 4 | - | Subtraction | e1 - e2 | L | +| 5 | << | Shift to the left | e1 << e2 | L | +| 5 | >> | Shift to the right | e1 >> e2 | L | +| 6 | < | Less | e1 < e2 | L | +| 6 | > | Greater | e1 > e2 | L | +| 6 | <= | Less than or equal | e1 <= e2 | L | +| 6 | >= | Greater than or equal | e1 >= e2 | L | +| 7 | == | Equal | e1 == e2 | L | +| 7 | != | Not equal | e1 != e2 | L | +| 8 | & | Bitwise AND | e1 & e2 | L | +| 9 | ^ | Bitwise exclusive OR | e1 ^ e2 | L | +| 10 | | | Bitwise OR | e1 | e2 | L | +| 11 | && | Logical AND | e1 && e2 | L | +| 12 | || | Logical OR | e1 || e2 | L | +| 13 | ?: | Conditional ternary | c1 ? e1 : e2 | R | +| 14 | = | Assignment | e1 = e2 | R | +| 14 | += | Addition with assignment | e1 += e2 | R | +| 14 | -= | Subtraction with assignment | e1 -= e2 | R | +| 14 | *= | Multiplication with assignment | e1 *= e2 | R | +| 14 | /= | Division with assignment | e1 /= e2 | R | +| 14 | %= | Division modulo with assignment | e1 %= e2 | R | +| 14 | <<= | Left shift with assignment | e1 <<= e2 | R | +| 14 | >>= | Right shift with assignment | e1 >>= e2 | R | +| 14 | &= | Bitwise AND with assignment | e1 &= e2 | R | +| 14 | |= | Bitwise OR with assignment | e1 |= e2 | R | +| 14 | ^= | Bitwise AND/OR with assignment | e1 ^= e2 | R | +| 15 | , | Comma | e1 , e2 | L | + +As we have seen, square brackets are used to specify the indices of array elements and, therefore, have one of the highest priorities. + +Along with operators that have been considered earlier, there are some still unknown ones here. + +We will learn the [scope resolution](/en/book/oop/classes_and_interfaces/classes_namespace_context) operator '::' within object-oriented programming (OOP). We will also need the dereferencing operator '.' at the same time. Identifiers of types (classes) and their properties, not expressions, act as their operands. + +Address-taking operator '&' is intended to pass the [function parameters by referencing](/en/book/basis/functions/functions_ref_value) and to obtain the [object addresses](/en/book/oop/classes_and_interfaces/classes_pointers) in OOP. In both cases, the operator is applied to a variable (LValue). + +Explicit typecasting operations will be considered in the [next chapter](/en/book/basis/conversion/conversion_explicit). diff --git a/skills/mql5/references/book/01-basis/0053-basis-conversion.md b/skills/mql5/references/book/01-basis/0053-basis-conversion.md new file mode 100644 index 0000000..69a4695 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0053-basis-conversion.md @@ -0,0 +1,19 @@ +# Type conversion + +In this section, we will consider the concept of type conversion, limiting ourselves to built-in data types for now. Later, after studying OOP, we will supplement it with the nuances inherent in object types. + +Type conversion in MQL5 is the process of changing the data type of a variable or expression. MQL5 supports three main types of type conversion: implicit, arithmetic, and explicit. + +[Implicit type conversion](/en/book/basis/conversion/conversion_implicit): + +- Occurs automatically when a variable of one type is used in a context that expects another type. For example, integer values can be implicitly converted to real values. + +[Arithmetic type conversion](/en/book/basis/conversion/conversion_arithmetic): + +- Arises during arithmetic operations with operands of different types. The compiler attempts to maintain maximum accuracy but warns about potential data loss. For instance, in integer division, the result is converted to a real type. + +[Explicit type conversion](/en/book/basis/conversion/conversion_explicit): + +- Gives the programmer control over type conversion. It is done in two forms: C-style ((target)) and "functional" style (target()). It is used when you need to explicitly instruct the compiler to perform a conversion between types, for example, when rounding real numbers or when successive type conversions are required. + +Understanding the differences between implicit, arithmetic, and explicit type conversion is crucial for ensuring the correct execution of operations and avoiding data loss. This knowledge helps programmers effectively utilize this mechanism in MQL5 development. diff --git a/skills/mql5/references/book/01-basis/0054-basis-conversion-conversion-implicit.md b/skills/mql5/references/book/01-basis/0054-basis-conversion-conversion-implicit.md new file mode 100644 index 0000000..9c9c085 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0054-basis-conversion-conversion-implicit.md @@ -0,0 +1,40 @@ +# Implicit type conversion + +Type conversion occurs automatically if one type is used at some point in the source code, but another is expected, and there are conversion rules between them. Such conversion is called an implicit type conversion and may not always correspond to the programmer's intent. In addition, some conversion operations have side effects, and the compiler, not knowing whether their use is intentional, highlights the corresponding lines of code with warnings. To solve these problems, there is an explicit type conversion syntax (see [Explicit type casting](/en/book/basis/conversion/conversion_explicit)). + +We have already seen several rules for implicit type conversion while studying types and variables. + +Specifically, if a value of type other than boolean is assigned to a bool variable, then the value 0 is regarded as false, and all the rest as true. In the more general case, all expressions that assume the presence of logical conditions are converted to type bool. For example, the first operand of a ternary conditional operator is always converted into a bool. + +But if a value of type bool is assigned to a numeric type, then true becomes 1, and false becomes 0. + +When a real number is assigned to an integer type variable, the fractional part is discarded (the compiler issues a warning). When an integer, on the other hand, is assigned to a variable of real type, precision can be lost (the compiler also issues a warning). We have already talked about this in the sections on [Integer numbers](/en/book/basis/builtin_types/integer_numbers) and [Real numbers](/en/book/basis/builtin_types/float_numbers). + +If we have integer and floating point numbers, everything is converted to floating point numbers of the maximum size used (usually double, unless you explicitly specify float or the numeric literal has a suffix 'f', for example1234.56789f). + +For integers of different sizes, there are also conversion rules: they expand if necessary, which means that they increase to the size of the largest integer type used in the expression (see [Arithmetic type conversions](/en/book/basis/conversion/conversion_arithmetic)). + +In addition to expressions, we often need to implicitly convert types during initialization and assignment, when the types to the right and left of the '=' sign do not match. The same conversion rules apply when passing values through function parameters and returning results from functions (for further details please see the [Functions](/en/book/basis/functions) section). + +Considering the above, a large number of conversions can be performed in one line of code. If this causes compiler warnings, it's a good idea to make sure the conversion is intentional and eliminate warnings by inserting an explicit type conversion. + +``` +short s = 10; +long n = 10; +int p = s * n + 1.0; + +``` + +In this example, when performing a multiplication, the type of the variable s is extended to the type of the second operand long and an intermediate result of type long is obtained. Because the constant 1.0 is of type double, the result of the product is converted to double before addition. The overall result is also of type double; however, the variable p is of type int and therefore an implicit conversion from double to int is performed. + +The special types datetime and color are processed according to the rules of integers with lengths of 8 and 4 bytes, respectively. But for date and time, there is a stricter limit on the maximum value - 32535244799, which corresponds to D'3000.12.31 23:59:59'. + +Most types can be implicitly converted to and from strings, but the results are not always adequate, so the compiler issues warnings "implicit conversion from 'number' to 'string'" and "implicit conversion from 'string' to 'number'" so that the programmer can check them. For example, converting a string to an integer allows the string to contain only digits and '+'/'-' characters at the beginning. Converting from a string to a real allows, in addition to numbers, the presence of a dot '.' and notation with "exponent" ('e' or 'E', e.g. +1.2345e-1). If an unsupported character (for example, a letter) is encountered in the string, the rest of the string is discarded in full. + +For example, the string date and time ("2021.12.12 00:00") cannot be assigned without losses to a variable of type datetime because datetime is an integer (number of seconds). In this case, reading the number from the string will end when the first point is reached, i.e. the number will get the value 2021. This number of seconds corresponds to the 34th minute of the year 1970. + +There are special functions for such conversions (see section [Data Transformation](/en/book/common/conversions/conversions_numbers)). + +The only direction of implicit and explicit type conversion that is forbidden is from string to bool. The compiler in such cases shows the error message "cannot implicitly convert type 'string' to 'bool'". + +Examples from this chapter are provided in TypeConversion.mq5. diff --git a/skills/mql5/references/book/01-basis/0055-basis-conversion-conversion-arithmetic.md b/skills/mql5/references/book/01-basis/0055-basis-conversion-conversion-arithmetic.md new file mode 100644 index 0000000..6ea482e --- /dev/null +++ b/skills/mql5/references/book/01-basis/0055-basis-conversion-conversion-arithmetic.md @@ -0,0 +1,102 @@ +# Arithmetic type conversions + +In arithmetic calculation and comparison expressions, values of different types are often used as operands. To process them correctly, it is necessary to bring the types to a certain "common denominator". The compiler attempts to do this without the programmer's intervention unless the programmer has specified explicit conversion rules (see [Explicit type conversion](/en/book/basis/conversion/conversion_explicit)). In this case, the compiler, whenever possible, tries to preserve the maximum precision when it comes to numbers. In particular, it produces an increase in the capacity of integer numbers and the transition from integer to real numbers (if they are involved). + +Integer expansion implies conversion of bool, char, unsigned char, short, unsigned short to int (or unsigned int if int isn't big enough to store specific numbers). Large values can be converted to long and unsigned long. + +If the type of the variable is not able to store the result of the type that was obtained when the expression was evaluated, the compiler will issue a warning: + +``` +double d = 1.0; +int x = 1.0 / 10; // truncation of constant value +int y = d / 10;   // possible loss of data due to type conversion + +``` + +The expression to initialize the variables x and y contains the real number 1.0, so the other operands (constant 10 in this case) are converted to double, and the result of division will also be of type double. However, the type of variables is int, and therefore an implicit conversion to it takes place. + +Calculation 1.0 / 10 is done by the compiler during compilation and therefore it gets a constant of type double (0.1). Of course, in practice, it is unlikely that the initializing constant will exceed the size of the receiving variable. Therefore, the compiler warning "truncation of constant value" can be considered exotic. It just shows the problem in the most simplified way. + +However, as a result of variable-based calculations, similar data loss can also occur. The second compiler warning we see here ("possible loss of data due to type conversion") occurs much more frequently. Moreover, the loss is possible not only when converting from real type to integer, but also vice versa. + +``` +double f = LONG_MAX; // truncation of constant value +long m1 = 1000000000; +f = m1 * m1;         // possible loss of data due to type conversion + +``` + +As we know, type double cannot accurately represent large integers (although its range of valid values is much larger than long). + +Another warning we might encounter due to type mismatch: "integral constant overflow". + +``` +long m1 = 1000000000; +long m2 = m1 * m1;                 // ok: m2 = 1000000000000000000 +long m3 = 1000000000 * 1000000000; // integral constant overflow +                                   // m3 = -1486618624 + +``` + +Integer constants in MQL5 have type int, so the multiplication of million by million is performed taking into account the range of this type, which is equal to INT_MAX (2147483647). The value 1000000000000000000 causes an overflow, and m3 gets the remainder after dividing this value by the range (more on this in the sidebar below). + +The fact that the receiving variable m3 has type long does not mean that the values ​​in the expression must be converted to it beforehand. This only happens at the moment of assignment. In order for the multiplication to be performed according to the rules of long, you need to somehow specify the type long directly in the expression itself. This can be done with an explicit conversion or by using variables. In particular, obtaining the same product using a variable m1 of type long (such as m1 * m1) leads to the correct result in m2. + +Signed and unsigned integers + +  + +Programs are not always written perfectly, with protection from all possible failures. Therefore, sometimes it happens that the integer number obtained during the calculations does not fit into the variable of the selected integer type. Then it gets the remainder of dividing this value by the maximum value (M) that can be written in the corresponding number of bytes (type size), plus 1. So for integer types with sizes from 1 to 4 bytes, M + 1 is, respectively, 256, 65536, 4294967296, and 18446744073709551616. + +  + +But there is a nuance for signed types. As we know, for signed numbers, the total range of values ​​is divided approximately equally between positive and negative areas. Therefore, the new "residual" value may in 50% of cases exceed the positive or negative limit. In this case, the number turns into the "opposite": it changes sign and ends up at a distance M from the original one. + +  + +It is important to understand that this transformation occurs only due to a different interpretation of the bit state in the internal representation, and the state itself is the same for signed and unsigned numbers. + +  + +Let's explain this with an example for the smallest integer types: char and uchar. + +  + +Since unsigned char can store values ​​from 0 to 255, 256 maps to 0, -1 maps to 255, 300 maps to 44, and so on. If we try to write 300 into a regular signed char, we also get 44, because 44 is in the range from 0 to 127 (the positive range of char). However, if you set the variables char and uchar to 3000, the picture will be different. The remainder of 3000 divided by 256 is 184. It ends up in uchar unchanged. However, for char, the same combination of bits results in -72. It is easy to check that 184 and -72 differ by 256. + +In the following example, it is easy to spot the problem thanks to the compiler warning. + +``` +char c = 3000;      // truncation of constant value +Print(c);           // -72 +uchar uc = 3000;    // truncation of constant value +Print(uc);          // 184 + +``` + +However, if you get an extra large number during the calculation, there will be no warning. + +``` +char c55 = 55; +char sm = c55 * c55;  // ok!  +Print(sm);            // 3025 -> -47 +uchar um = c55 * c55; // ok! +Print(um);            // 3025 -> 209 + +``` + +A similar effect can occur when signed and unsigned integer numbers of the same size are used in the same expression since the signed operand is converted to unsigned. For example: + +``` +uint u = 11; +int i = -49; +Print(i + i); // -98 +Print(u + i); // 4294967258 = 4294967296 - 38 + +``` + +When two negative integers add up, we get the expected result. The second expression maps the sum of -38 to the "opposite" unsigned number 4294967258. + +Mixing signed and unsigned types in the same expression is not recommended because of these potential issues. + +Besides that, if we subtract something from an unsigned integer, we need to make sure that the result doesn't come out negative. Otherwise, it will be converted to a positive number and can distort the idea of the algorithm, in particular, the idea of the [while](/en/book/basis/statements/statements_while)[ loop](/en/book/basis/statements/statements_while) which checks the variable for the "greater than or equal to zero" condition: since unsigned numbers are always non-negative, we can easily get an infinite loop, i.e. a program hang. diff --git a/skills/mql5/references/book/01-basis/0056-basis-conversion-conversion-explicit.md b/skills/mql5/references/book/01-basis/0056-basis-conversion-conversion-explicit.md new file mode 100644 index 0000000..1f38c2d --- /dev/null +++ b/skills/mql5/references/book/01-basis/0056-basis-conversion-conversion-explicit.md @@ -0,0 +1,46 @@ +# Explicit type conversion + +For explicit type conversion, MQL5 supports two forms of notation: in the C style and "functional". C-style has the following syntax: + +``` +target t = (target)s; + +``` + +Where target is the name of the target type. Any expression can be a data source s. If any operations are performed in it, you must enclose the expression in parentheses so that the type conversion applies to the entire expression. + +An alternative "functional" syntax looks like this: + +``` +target t = target(s); + +``` + +Let's look at a couple of examples. + +``` +double w = 100.0, v = 7.0; +int p = (int)(w / v);      // 14 + +``` + +Here, the result of dividing two real numbers is explicitly converted to the type int. Thus, the programmer confirms their intention to discard the fractional part, and the compiler will not issue warnings. It should be noted that MQL5 has a group of functions for rounding real numbers in various ways (see [Math functions](/en/book/common/maths)). + +If, on the contrary, you want to perform an operation on integer numbers with a real result, you need to apply type conversion to the operands (in the expression itself): + +``` +int x = 100, y = 7; +double d = (double)x / y;  // 14.28571428571429 + +``` + +Converting one of the operands is enough to automatically convert the rest to the same type. + +If necessary, you can perform several type conversion operations sequentially. Because the conversion operation is right-associative, the target types will be applied in order from right to left. In the following example, we convert the quotient to type float (this conversion allows for a more compact, fewer-character representation of the value), and then to string. Without an explicit conversion to string, we would get a compiler warning "implicit number to string conversion". + +``` +Print("Result:" + (string)(float)(w / v)); // Result:14.28571 + +``` + +Don't use explicit type conversion just to avoid a compiler warning. If it has no practical basis, you are masking a potential error in the program. diff --git a/skills/mql5/references/book/01-basis/0057-basis-statements.md b/skills/mql5/references/book/01-basis/0057-basis-statements.md new file mode 100644 index 0000000..580969b --- /dev/null +++ b/skills/mql5/references/book/01-basis/0057-basis-statements.md @@ -0,0 +1,11 @@ +# Statements + +So far, we've learned about data types, variable declarations, and their use in expressions for calculations. However, these are only small bricks in the building with which the program can be compared. Even the simplest program consists of larger blocks that allow you to group related data processing operations and control the sequence of their execution. These blocks are called statements, and we have actually already used some of them. + +In particular, the declaration of a variable (or several variables) is a statement. Assigning the expression evaluation result to a variable is also a statement. Strictly speaking, the assignment operation itself is part of the expression, so it is more correct to call such a statement a statement of expression. By the way, an expression may not contain an assignment operator (for example, if it simply calls some function that does not return a value, such as Print("Hello");). + +Program execution is the progressive execution of statements: from top to bottom and from left to right (if there are several statements on one line). In the simplest case, their sequence is performed linearly, one after the other. For most programs, this is not enough, so there are various control statements. They allow you to organize loops (repeating calculations) in programs and the selection of algorithm operation options depending on the conditions. + +Statements are special syntactic constructions that represent the source text written according to the rules. Statements of a particular type have their own rules, but there is something in common. Statements of all types end with a ';' except for the [compound statement](/en/book/basis/statements/statements_compound). It can do without a semicolon because its beginning and end are set by a pair of curly brackets. It is important to note that thanks to the compound statement, we can include sets of statements inside other statements, building arbitrary hierarchical structures of algorithms. + +In this chapter, we will get acquainted with all types of MQL5 control statements, as well as consolidate the features of declaration and expression statements. diff --git a/skills/mql5/references/book/01-basis/0058-basis-statements-statements-compound.md b/skills/mql5/references/book/01-basis/0058-basis-statements-statements-compound.md new file mode 100644 index 0000000..10bc8ad --- /dev/null +++ b/skills/mql5/references/book/01-basis/0058-basis-statements-statements-compound.md @@ -0,0 +1,18 @@ +# Compound statements (blocks of code) + +A compound statement is a generic container for other statements enclosed in curly brackets '{' and '}'. Such a block of code can be used to define the body of a function, after the header of other control statements if they require more than one controlled statement, or simply as a nested block on its own within the body of a function or other statement. This allows you to create a local, limited scope for variables. We already talked about this in the section [Context, scope, and lifetime of variables](/en/book/basis/variables/scope_and_lifetime). + +In a generalized form, a compound statement can be described as follows: + +``` +{ +[statements] +} + +``` + +In such a schematic description, any fragment enclosed in semicircular brackets and with the superscripted opt indicates that it is optional. In this case, there may not be any nested statements inside the block. + +In the following sections, we will see how compound statements are used in combination with other kinds of statements and what they can contain. + +There is one nuance that is worth emphasizing: after the description of the compound statement, the semicolon ';' is not required. This distinguishes it from all other statements. diff --git a/skills/mql5/references/book/01-basis/0059-basis-statements-statements-declaration.md b/skills/mql5/references/book/01-basis/0059-basis-statements-statements-declaration.md new file mode 100644 index 0000000..9c31ad4 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0059-basis-statements-statements-declaration.md @@ -0,0 +1,173 @@ +# Declaration/definition statements + +The declaration of a variable, array, function, or any other named element of a program (including structures and classes, which will be discussed in Part 3) is a statement. + +The declaration must contain the type and identifier of the element (see [Declaring and defining variables](/en/book/basis/variables/define_vs_declare)), as well as an optional initial value for [initialization](/en/book/basis/variables/initialization). Also, when declaring, additional modifiers can be specified that change certain characteristics of the element. In particular, we already know the [static](/en/book/basis/variables/static_variables) and [const](/en/book/basis/variables/const_variables) modifiers, and more will be added soon. Arrays require an additional specification of the dimension and number of elements (see [Description of arrays](/en/book/basis/arrays/arrays_declaration)), while functions require a list of parameters (for further details please see [Functions](/en/book/basis/functions/functions_definition)). + +The variable declaration statement can be summarized as follows: + +``` +[modifiers] identifier type +  [= initialization expressions] ; + +``` + +For an array, it looks like this: + +``` +[modifiers] identifier type [ [size_1]ᵒᵖᵗ ] [ [size_N] ]ᵒᵖᵗ(3) +  [ = { initialization_list } ]ᵒᵖᵗ ; + +``` + +The main difference is the mandatory presence of at least one pair of square brackets (the size inside them can be indicated or not; depending on that, we get a fixed or dynamically distributed array). In total, up to 4 pairs of square brackets are allowed (4 is the maximum supported number of measurements). + +In many cases, a declaration can simultaneously act as a definition, i.e. it reserves memory for the element, determines its behavior, and makes it possible to use it in the program. Specifically, the declaration of a variable or array is also a definition. From this point of view, a declaration statement can be called a definition statement all the same, but this has not become a common practice. + +Our basic knowledge of functions is enough to reliably assume what their definition should look like: + +``` +type identifier ( [list_of_arguments] ) +{ +  [statements] +} + +``` + +Type, identifier, and list of arguments make up the function header. + +Please note that this is a definition since this description contains both the external attributes of the function (interface) and statements that define its internal essence (implementation). The latter is done with a block of code formed by a pair of curly brackets and immediately following the function header. As you might guess, this is an example of the compound statement we mentioned in [the previous section](/en/book/basis/statements/statements_compound). In this case, a terminological tautology is indispensable, since it is perfectly justified: the compound statement is part of the function definition statement. + +A little later, we will learn why and how to separate the interface description from the implementation and thereby achieve [function declaration](/en/book/basis/functions/functions_declaration) without defining it. We will also demonstrate the difference between a [declaration and a definition using the class](/en/book/oop/classes_and_interfaces/classes_declaration_definition) as an example. + +The declaration statement makes the new element available by its name in the context of the code block (see [Context, scope, and lifetime of variables](/en/book/basis/variables/scope_and_lifetime)) in which the statement is located. Recall that blocks form the local scope of objects (variables, arrays). In the first part of the book, we encountered this when describing the greeting function. + +In addition to local scopes, there is always a global scope, in which you can also use declaration statements to create elements that are accessible from anywhere in the program. + +If there is no static modifier in the declaration statement and it is located in some local block, then the corresponding element is created and initialized at the moment the statement is executed (strictly speaking, memory for all local variables inside the function is allocated, for the sake of efficiency, immediately upon entering the function, but they are not yet formed at that moment). + +For example, the following declaration of the variable i at the beginning of the OnStart function ensures that such a variable will be created with the specified initial value (0) as soon as the function receives control (i.e., the terminal will call it because it is the main function of the script). + +``` +void OnStart() +{ +   int i = 0; +   Print(i); +    +   // error: 'j' - undeclared identifier +   // Print(j);  +   int j = 1; +} + +``` + +Thanks to the declaration in the first statement, the variable i is known and available in the subsequent lines of the function, in particular, in the second line with the call of the Print function, which displays the contents of the variable in the log. + +The variable j described in the last line of the function will be created just before the end of the function (this, of course, is meaningless, but clear). Therefore, this variable is not known in all earlier strings of this function. An attempt to output j to the log using a commented Print call will result in an "undeclared identifier" compilation error. + +Elements declared this way (inside code blocks and without the static modifier) are called automatic, because the program itself allocates memory for them when entering the block and destroys them when exiting the block (in our case, after exiting the function). Therefore, the area of memory in which this happens is called the stack ("last in, first out"). + +Automatic elements are created in the order in which the declaration statements are executed (first i, then j). Destruction is performed in reverse order (first j, then i). + +If a variable is declared without initialization and starts to be used in subsequent statements (for example, to the right of the '=' sign) without first writing a meaningful value into it, the compiler issues a warning: "possible use of uninitialized variable". + +``` +void OnStart() +{ +   int i, p; +   i = p; // warning: possible use of uninitialized variable 'p' +} + +``` + +If a declaration statement has the static modifier, the corresponding element is created only once when the statement is executed for the first time, and remains in memory, regardless of exit and possible subsequent entries and exits in the same block of code. All such static members are removed only when the program is unloaded. + +Despite the increased lifetime, the scope of such variables is still limited to the local context in which they are defined, and can only be accessed from later statements (located below in the code). + +In contrast, declaration statements in the global context create their elements in the same order in which they appear in the source code, immediately after the program is loaded (before any standard start function is called, such as OnStart for scripts). Global objects are deleted in reverse order when the program is unloaded. + +To demonstrate the aforementioned, let's create a more "cunning" example (StmtDeclaration.mq5). Recalling the skills gained in the first part, in addition to OnStart, we will write a simple function Init, which will be used in variable initialization expressions and will log a sequence of calls. + +``` +int Init(const int v) +{ +   Print("Init: ", v); +   return v; +} + +``` + +The Init function accepts a single parameter v of integer type int, the value of which is returned to the calling code ([return](/en/book/basis/statements/statements_return)[ statement](/en/book/basis/statements/statements_return)). + +This allows using it as a wrapper to set the initial value of a variable, for example, for two global variables: + +``` +int k = Init(-1); +int m = Init(-2); + +``` + +The value of the passed argument gets into the variables k and m by calling the function and returning from it. However, inside Init, we additionally output the value with Print, and thus we can track how the variables are created. + +Note that we cannot use the Init function in the initialization of global variables above its definition. If we try to move the k variable declaration above the Init declaration, we get the error "'Init' is an unknown identifier". This limitation only works for the initialization of global variables, because functions are also defined globally, and the compiler builds a list of such identifiers in one go. In all other cases, the order of defining functions in the code is not important, because the compiler first registers them all in the internal list, and then mutually links their calls from blocks. In particular, you can move the entire Init function and the declaration of the global variables k and m below the OnStart function - it will not break anything. + +Inside the OnStart function, we will describe several more variables using Init: local i and j, as well as static n. For simplicity, all variables are given unique values so that they can be distinguished. + +``` +void OnStart() +{ +   Print(k); +    +   int i = Init(1); +   Print(i); +   // error: 'n' - undeclared identifier +   // Print(n); +   static int n = Init(0); +   // error: 'j' - undeclared identifier +   // Print(j); +   int j = Init(2); +   Print(j); +   Print(n); +} + +``` + +Comments here show erroneous attempts to call the relevant variables before they are defined. + +Run the script and get the following log: + +``` +Init: -1 +Init: -2 +-1 +Init: 1 +1 +Init: 0 +Init: 2 +2 +0 + +``` + +As we can see, the global variables were initialized before the OnStart function was called, and exactly in the order in which they were encountered in the code. Internal variables were created in the same sequence as their declaration statements were written. + +If a variable is defined but not used anywhere, the compiler will issue a "variable 'name' not used" warning. This is a sign of a potential programmer error. + +Looking ahead, let's say that with the help of declaration/definition statements, not only data elements (variables, arrays) or functions, but also new user-defined types (structures, classes, templates, namespaces) that are not yet known to us can be introduced into the program. Such statements can only be made at the global level, that is, outside of all functions. + +It is also impossible to define a function within a function. The following code will not compile: + +``` +void OnStart() +{ +   int Init(const int v) +   { +      Print("Init: ", v); +      return v; +   } +   int i = 0; +} + +``` + +The compiler will generate an error: "function declarations are allowed on global, namespace, or class scope only". diff --git a/skills/mql5/references/book/01-basis/0060-basis-statements-statements-expression.md b/skills/mql5/references/book/01-basis/0060-basis-statements-statements-expression.md new file mode 100644 index 0000000..1ea5799 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0060-basis-statements-statements-expression.md @@ -0,0 +1,64 @@ +# Simple statements (expressions) + +Simple statements contain [expressions](/en/book/basis/expressions), such as assigning new values or calculation results to variables, as well as function calls. + +Formally, the syntax looks like this: + +``` +expression ; + +``` + +The semicolon at the end is important here. Since MQL5 source codes support free formatting, the ';' is the only delimiter that tells the compiler where the previous statement ended and the next one began. As a rule, statements are written on separate lines, for example, like this: + +``` +int i = 0, j = 1, k;   // declaration statement +++i;                   // simple statement +j += i;                // simple statement +k = (i + 1) * (j + 1); // simple statement +Print(i, " ", j);      // simple statement + +``` + +However, the rules do not prohibit shorthand code writing: + +``` +int i=0,j=1;++i;j+=i;k=(i+1)*(j+1);Print(i," ",j); + +``` + +If it weren't for the ';', adjacent expressions could silently "stick together" and lead to unintended results. For example, the expression x = y - 10 * z could well be two: x = y; and -10 * z; (-10 with a unary minus). How is this possible? + +The fact is that it is syntactically permissible to write a statement that actually works in vain, i.e., does not save the result. Here is another example: + +``` +i + j; // warning: expression has no effect + +``` + +The compiler issues an "expression has no effect" warning. The possibility to construct such expressions is necessary because the object types, which we will learn in [Part 3](/en/book/oop), allow for the [operator overloading](/en/book/oop/classes_and_interfaces/classes_operator_overloading), i.e., we can replace the usual meaning of operator symbols with some specific actions. Then, if the type of i and j is not int, but some class with an overridden addition operation, such a notation will have an effect, and the compiler will not issue a warning. + +Simple statements can only be written inside compound statements. For example, calling the Print function outside of a function will not work: + +``` +Print("Hello ", Symbol()); +void OnStart() +{ +} + +``` + +We will get a cascade of errors:: + +``` +'Print' - unexpected token, probably type is missing? +'Hello, ' - declaration without type +'Hello, ' - comma expected +'Symbol' - declaration without type +'(' - comma expected +')' - semicolon expected +')' - expressions are not allowed on a global scope + +``` + +The most relevant, in this case, is the last one: "expressions are not allowed in the global context." diff --git a/skills/mql5/references/book/01-basis/0061-basis-statements-statements-control.md b/skills/mql5/references/book/01-basis/0061-basis-statements-statements-control.md new file mode 100644 index 0000000..de4e3cd --- /dev/null +++ b/skills/mql5/references/book/01-basis/0061-basis-statements-statements-control.md @@ -0,0 +1,38 @@ +# Overview of control statements + +Control statements are designed to organize the non-linear execution of other statements, including declarations, expressions, and nested control statements. They can be divided into 3 types: + +- repetition statements, or loops +- conditional statements for choosing one of several branches of alternative actions +- jump statements that change, if necessary, the standard behavior of the first two types of statements + +Repeat and select statements consist of a header (each with a different syntax) followed by a controlled statement. If a managed part needs to specify multiple statements, it uses a compound statement. This feature is not available for jump statements. They only move the internal pointer, based on which the program determines which statement is currently to be executed, according to special rules, which we will discuss in the following sections. + +In the simplest case, without control statements, the statements are executed sequentially, one after the other, as they are written in the code block (in particular, in the body of the main function OnStart for scripts). If an expression with a call to another function is encountered in a code block, the program, according to the same linear principle, begins to execute statements inside the called function, and when they are all executed, it will return to the calling code block, and execution will continue on the next statement after the function call. Control statements can significantly change this logic of work. + +You can use selection inside loops or vice versa, and the nesting level is unlimited. However, too much nesting makes the program difficult to understand for the programmer. Therefore, it is recommended to allocate (transfer) code blocks into functions (one or several): inside each function, it makes sense to maintain a nesting level of no more than 2-3. + +The following repetition statements are supported in MQL5: + +- for loop +- while loop +- do loop + +All loops allow one or more statements to be executed a given number of times or until some boolean condition is met. Executing the contents of a loop once is called an iteration. As a rule, arrays are processed in loops or periodic repeating actions are performed (usually in [scripts](/en/book/applications/script_service/scripts) or [services](/en/book/applications/script_service/services)). + +Conditional statements include: + +- selection with if +- selection with switch + +The former allows you to specify one or more conditions, depending on the truth or falsity of which the options assigned to them (one or more statements) will be executed. The latter evaluates an expression of an integer type and selects one of several alternatives based on its value. + +Finally, jump statements are: + +- break +- continue +- return + +Later we will consider each of them in detail. + +Unlike C++, MQL5 does not have a go to statement. diff --git a/skills/mql5/references/book/01-basis/0062-basis-statements-statements-for.md b/skills/mql5/references/book/01-basis/0062-basis-statements-statements-for.md new file mode 100644 index 0000000..9d34ca8 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0062-basis-statements-statements-for.md @@ -0,0 +1,167 @@ +# For loop + +This loop is implemented by a statement with the for keyword, hence the name. In a generalized form, it can be described as follows: + +``` +for ( [initialization] ; [condition] ; [expression] ) +  loop body + +``` + +In the title, after the word 'for', the following is indicated in parentheses: + +- Initialization: a statement for one-time initialization before the start of the loop; +- Condition: a boolean condition that is checked at the beginning of each iteration, and the loop runs as long as it is true; +- Expression: formula of calculations performed at the end of each iteration, when all statements in the loop body have been passed. + +The loop body is a simple or compound statement. + +All three header components are optional and may be omitted in any combination, including their absence. + +Initialization may include the declaration of variables (along with setting initial values) or the assignment of values to already existing variables. Such variables are called loop variables. If they are declared in the header, then their scope and lifetime are limited to the loop. + +The loop starts executing if, after initialization, the condition is true, and continues executing for as long as it is true at the beginning of each subsequent iteration. If during the next check, the condition is violated, the loop exits, i.e., control is transferred to the statement written after the loop and its body. If the condition is false before the start of the loop (after initialization), it will never be executed. + +The condition and expression usually include loop variables. + +Executing a loop means executing its body. + +The most common form of the for loop has a single loop variable that controls the number of iterations. In the following example, we calculate the squares of the numbers in the a array. + +``` +int a[] = {1, 2, 3, 4, 5, 6, 7}; +const int n = ArraySize(a); +for(int i = 0; i < n; ++i) +   a[i] = a[i] * a[i]; +ArrayPrint(a);    // 1  4  9 16 25 36 49 +// Print(i);      // error: 'i' - undeclared identifier + +``` + +This loop is executed in the following steps: + +1. A variable i with an initial value of 0 is created. +2. The condition is checked of whether the variable i is less than the size of the loop n. As long as it is true, the loop continues. If it is false, we jump to the statement calling the ArrayPrint function. +3. If the condition is true, the statements of the loop body are executed. In this case, the i-th element of the array gets the product of the initial value of this element by itself, i.e. the value of each element is replaced by its square. +4. The variable i is incremented by 1. + +Then everything repeats, starting from step 2. After exiting the loop, its variable i is destroyed, and an attempt to access it will cause an error. + +The expression for step 4 can be of arbitrary complexity, not just an increment of the loop variable. For example, to iterate over even or odd elements, one could write i += 2. + +Regardless of how many statements make up the body of the loop, it is recommended to write it on a separate line (lines) from the header. This makes the step-by-step debugging process easier. + +Initialization may include multiple variable declarations, but they must be of the same type because they are one statement. For example, to rearrange elements in reverse order, you can write such a loop (this is just a demonstration of the loop, there is a built-in function ArrayReverse to reverse the order in an array, see [Copying and editing arrays](/en/book/common/arrays/arrays_edit)): + +``` +for(int i = 0, j = n - 1; i < n / 2; ++i, --j) +{ +   int temp = a[i]; +   a[i] = a[j]; +   a[j] = temp; +} +ArrayPrint(a);    // 49 36 25 16  9  4  1 + +``` + +The auxiliary variable temp is created and deleted on each pass of the loop, but the compiler allocates memory for it only once, as for all local variables, when entering the function. This optimization works well for built-in types. However, if [a custom class object](/en/book/oop) is described in the loop, then its constructor and destructor will be called at each iteration. + +It is acceptable to change the loop variable in the loop body, but this technique is only used in very exotic cases. It is not recommended to do this, as this may cause errors (in particular, processed elements can be skipped or execution can get into an infinite loop). + +To demonstrate the ability to omit header components, let's imagine the following problem: We need to find the number of elements of the same array the sum of which is less than 100. To do this, we need a counter variable k defined before the loop because it must continue to exist after its completion. We will also create the sum variable to calculate the sum on a cumulative basis. + +``` +int k = 0, sum = 0; +for( ; sum < 100; ) +{ +  sum += a[k++]; +} +  +Print(k - 1, " ", sum - a[k - 1]); // 2 85 + +``` + +Thus, there is no need to do initialization in the header. In addition, the k counter is incremented using a postfix increment directly in the expression that calculates the sum (when accessing an array element). Therefore, we do not need an expression in the title. + +At the end of the loop, we print out k and the sum minus the last added element, because it was the one that exceeded our limit of 100. + +Note that we are using a compound block even though there is only one statement in the loop body. This is useful because when the program grows, everything is already done for adding additional statements inside the brackets. In addition, this approach guarantees a uniform style for all loops. But the choice, in any case, is up to the programmer. + +In the explicit, maximally abbreviated version, the cycle header might look like this: + +``` +for( ; ; ) +{ +   // ...       // periodic actions +   Sleep(1000); // pause the program for 1 second +} + +``` + +If there are no statements in the body of such a loop that would interrupt the loop due to some conditions, it will be executed indefinitely. We'll learn how to break and test conditions in [Break ](/en/book/basis/statements/statements_break)[jump](/en/book/basis/statements/statements_break) and [If ](/en/book/basis/statements/statements_if)[selection](/en/book/basis/statements/statements_if) respectively. + +Such looping algorithms are usually used in services (they are designed for constant background work) to monitor the state of the terminal or external network resources. They usually contain statements that pause the program at a specified interval, for example, using the built-in function [Sleep](/en/book/common/timing/timing_sleep). Without this precaution, an infinite loop will load 100% of one processor core. + +Script StmtLoopsFor.mq5 contains an infinite loop at the end, but it is for demonstration purposes only. + +``` +for( ; ; ) +{ +   Comment(GetTickCount()); +   Sleep(1000); // 1000 ms +   +   // the loop can be exited only by deleting the script at the user's command +   // after 3 seconds of waiting we will get the message 'Abnormal termination' +} +Comment("");  // this line will never be executed + +``` + +In the loop, once per second, the computer's internal timer ([GetTickCount](/en/book/common/timing/timing_count)) is displayed using the [Comment](/en/book/common/output/output_comment) function: the value is displayed in the upper left corner of the chart. Only the user can interrupt the loop by deleting the entire script from the chart (the "Delete" button in the Experts dialog). This code does not check for such user requests to stop inside the loop, although there is a built-in function [IsStopped](/en/book/common/environment/env_stop) for this purpose. It returns true if the user has given the command to stop. In the program, especially if there are loops and long-term calculations, it is desirable to provide for checking the value of this function and voluntarily terminate the loop and the entire program upon receipt of true. Otherwise, the terminal will forcibly terminate the script after 3 seconds of waiting (with output to the "Abnormal termination" log), which will happen in this example. + +A better version of this loop should be: + +``` +for( ; !IsStopped(); ) // continue until user interrupt +{ +   Comment(GetTickCount()); +   Sleep(1000); // 1000 ms +} +Comment("");    // will clear the comment + +``` + +However, this loop would be better implemented using another repeat statement [while](/en/book/basis/statements/statements_while). As a rule of thumb, a for loop should only be used when there is an obvious loop variable and/or a predetermined number of iterations. In this case, these conditions are not met. + +Loop variables are usually integers, although other types are allowed, such as double. This is due to the fact that the very logic of the loop operation implies the numbering of iterations. In addition, it is always possible to calculate the necessary real numbers from an integer index, and with greater accuracy. For example, the following loop iterates over values from 0.0 to 1.0 in increments of 0.01: + +``` +for(double x = 0.0; x < 1.0; x += 0.01) { ... } + +``` + +It can be replaced by a similar loop with an integer variable: + +``` +for(int i = 0; i < 100; ++i) { double x = i * 0.01; ... } + +``` + +In the first case, when adding x += 0.01, the error of floating-point calculations gradually accumulates. In the second case, each value x is obtained in one operation i * 0.01, with the maximum available precision. + +It is customary to give loop variables the following single-letter names, for example, i, j, k, m, p, q. Multiple names are required when loops are nested or both forward (increasing) and backward (decreasing) indexes are calculated within the same loop. + +By the way, here is an example of a nested loop. The following code calculates and stores the multiplication table in a two-dimensional array. + +``` +int table[10][10] = {0}; +for(int i = 1; i <= 10; ++i) +{ +   for(int j = 1; j <= 10; ++j) +   { +      table[i - 1][j - 1] = i * j; +   } +} +ArrayPrint(table); + +``` diff --git a/skills/mql5/references/book/01-basis/0063-basis-statements-statements-while.md b/skills/mql5/references/book/01-basis/0063-basis-statements-statements-while.md new file mode 100644 index 0000000..c9c56eb --- /dev/null +++ b/skills/mql5/references/book/01-basis/0063-basis-statements-statements-while.md @@ -0,0 +1,76 @@ +# While loop + +This loop is described using the while keyword. It repeats the execution of controlled statements as long as the logical expression in its header is true. + +``` +while ( condition ) +  loop body + +``` + +The condition is an arbitrary expression of a boolean type. The presence of the condition is mandatory. If the condition is false before the start of the loop, the loop will never execute. + +Unlike C++, MQL5 does not support defining variables in the while loop header. + +Variables included in the condition must be defined before the loop. + +The loop body is a simple or compound statement. + +The while loop is usually used when the number of iterations is not defined. So, an example with the loop that outputs a computer timer counter every second can be written using a while loop and checking the stop flag (by calling the IsStopped function) as follows (StmtLoopsWhile.mq5): + +``` +while(!IsStopped()) +{ +   Comment(GetTickCount()); +   Sleep(1000); +} +Comment(""); + +``` + +Also, the while loop is convenient when the loop termination condition can be combined with the modification of variables in one expression. The next loop is executed until the variable i reaches zero (0 is treated as false). + +``` +int i = 5; +while(--i) // warning: expression not boolean +{ +   Print(i); +} + +``` + +However, in this case, the header expression is not boolean (and is implicitly converted to false or true). The compiler generates the relevant warning. It is desirable to always compose expressions taking into account the expected (according to the rules) characteristics. Below is the correct loop version: + +``` +int i = 5; +while(--i > 0) +{ +   Print(i); +} + +``` + +The loop can also be used with a simple statement (no block): + +``` +while(i < 10) +   Print(++i); + +``` + +Note that a simple statement ends with a semicolon. It also demonstrates that changing the variable being checked in the header is done inside the loop. + +When working with loops, be careful when using unsigned integers. For example, the next loop will never end, because its condition is always true (in theory, the compiler could issue warnings in such places, but it does not). After zero, the counter will "turn" into a large positive number (UINT_MAX) and the loop will continue. + +``` +uint i = 5; +while(--i >= 0) +{ +   Print(i); +} + +``` + +From the user's point of view, the MQL program will freeze (stop responding to commands), although it will still consume resources (processor and memory). + +while loops can be nested like other kinds of repetition statements. diff --git a/skills/mql5/references/book/01-basis/0064-basis-statements-statements-do.md b/skills/mql5/references/book/01-basis/0064-basis-statements-statements-do.md new file mode 100644 index 0000000..dfac2d7 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0064-basis-statements-statements-do.md @@ -0,0 +1,33 @@ +# Do loop + +This loop is similar to the while loop, but its condition is checked after the loop body. Due to this, controlled statements must be executed at least once. + +Two keywords, do and while, are used to describe the loop: + +``` +do +  loop body +while ( condition ) ; + +``` + +Thus, the loop header is separated, and after the logical condition in brackets, there should be a semicolon. The condition cannot be omitted. When it becomes false, the loop exits. + +Variables included in the condition must be defined before the loop. + +The loop body is a simple or compound statement. + +The following example calculates a sequence of numbers starting from 1, in which each next number is obtained by multiplying the previous one by the square root of two, the predefined constant M_SQRT2 (StmtLoopsDo.mq5). + +``` +double d = 1.0; +do +{ +   Print(d); +   d *= M_SQRT2; +} +while(d < 100.0); + +``` + +The process terminates when the number exceeds 100. diff --git a/skills/mql5/references/book/01-basis/0065-basis-statements-statements-if.md b/skills/mql5/references/book/01-basis/0065-basis-statements-statements-if.md new file mode 100644 index 0000000..b5b1097 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0065-basis-statements-statements-if.md @@ -0,0 +1,141 @@ +# If selection + +The if statement has several forms. In its simplest case, it executes the dependent statement if the specified condition is true: + +``` +if ( condition ) +  statement + +``` + +If the condition is false, the statement is skipped and the execution immediately jumps to the rest of the algorithm (subsequent statements, if any). + +The statement can be simple or compound. A condition is an expression of a boolean or castable type. + +The second form allows you to specify two branches of actions: not only for the true condition (statement_A) but also for the false (statement_B): + +``` +if ( condition ) +  statement_A +else +  statement_B + +``` + +Whichever of the controlled statements is executed, the algorithm will then continue following the statements below the if/else statement. + +For example, a script can follow a different strategy depending on the timeframe of the chart it is placed on. For this purpose, it is enough to analyze the value returned by the [Period](/en/book/applications/charts/charts_main_properties) built-in function. The value is of the [ENUM_TIMEFRAMES](/en/book/applications/timeseries/timeseries_symbol_period) enum type. If it is less than PERIOD_D1, it means short-term trading, otherwise, long-term trading (StmtSelectionIf.mq5). + +``` +if(Period() < PERIOD_D1) +{ +   Print("Intraday"); +} +else +{ +   Print("Interday"); +} + +``` + +As a statement in the else branch, it is allowed to specify the following operator if, and thus arrange them into a chain of successive checks. For example, the following fragment counts the number of capital letters and punctuation symbols (more precisely, non-Latin letters) in a string. + +``` +string s = "Hello, " + Symbol(); +int capital = 0, punctuation = 0; +for(int i = 0; i < StringLen(s); ++i) +{ +   if(s[i] >= 'A' && s[i] <= 'Z') +      ++capital; +   else if(!(s[i] >= 'a' && s[i] <= 'z')) +      ++punctuation; +       +} +Print(capital, " ", punctuation); + +``` + +The loop is organized through all the characters of the string (numbering starts from 0) and the [StringLen](/en/book/common/strings/strings_init) function returns the length of the string. The first if checks each character to see if it belongs to the range 'A' to 'Z' and, if successful, increments the capital counter by 1. If the character does not fall into this range, the second if is run, in which the condition for belonging to the range of lowercase letters (s[i] >= 'a' && s[i] <= 'z') is inverted with '!'. In other words, the condition means that the character is not in the given range. Given two consecutive checks, if the character is not an uppercase letter (else) and not a lowercase letter (the second if), we can conclude that the character is not a letter of the Latin alphabet. In this case, we increment the punctuation counter. + +The same checks could be written in a more detailed form, with '{...}' blocks for clarity. + +``` +int capital = 0, small = 0, punctuation = 0; +for(int i = 0; i < StringLen(s); ++i) +{ +   if(s[i] >= 'A' && s[i] <= 'Z') +   { +      ++capital; +   } +   else +   { +      if(s[i] >= 'a' && s[i] <= 'z') +      { +         ++small; +      } +      else +      { +         ++punctuation; +      } +   } +} + +``` + +The use of curly brackets helps to avoid logical errors associated which can occur when the programmer is only guided by indentation in the code. In particular, the most common problem is called the "hanging" else. + +When if statements are nested, sometimes there are fewer else branches than if. Here is one example: + +``` +factor = 0.0; +if(mode > 10) +   if(mode > 20) +      factor = +1.0; +else +   factor = -1.0; + +``` + +The indentation indicates what kind of logic the programmer meant: factor should become +1 when mode is greater than 20, remain equal to 0 when mode is between 10 and 20, and change to -1 otherwise (mode <= 10). But will the code work that way? + +In MQL5, each else is assumed to refer to the nearest previous if (which does not have a else). As a result, the compiler will treat the statements as follows: + +``` +factor = 0.0; +if(mode > 10) +   if(mode > 20) +      factor = +1.0; +   else +      factor = -1.0; + +``` + +So the factor will be -1 in the mode range from 10 to 20, and 0 for mode <= 10. The most interesting thing is that the program does not produce any formal errors, neither during compilation nor during execution. And yet it doesn't work correctly. + +To eliminate such subtle logical problems allows the placement of curly brackets. + +``` +if(mode > 10) +{ +   if(mode > 20) +      factor = +1.0; +} +else +   factor = -1.0; + +``` + +To keep the design consistent, it is desirable to use blocks in all branches of the statement if at least one block has already been required in it. + +When using the loop to check equality, take into account the possibility of a typo when one '=' is written instead of two characters '=='. This turns the comparison into an assignment, and the assigned value is analyzed as a logical condition. For example, + +``` +// should have been x == y + 1, which would give false and skip the if +if(x = y + 1) // warning: expression not boolean +{ +   // assigned x = 5 and treated x as true, so if is executed +} + +``` + +The compiler will produce a warning "expression not boolean". diff --git a/skills/mql5/references/book/01-basis/0066-basis-statements-statements-switch.md b/skills/mql5/references/book/01-basis/0066-basis-statements-statements-switch.md new file mode 100644 index 0000000..eef221a --- /dev/null +++ b/skills/mql5/references/book/01-basis/0066-basis-statements-statements-switch.md @@ -0,0 +1,117 @@ +# Switch selection + +The switch operator provides the ability to choose one of several algorithm options. As a rule, the number of options is significantly higher than two, because otherwise, it is easier to use the if/else statement. In theory, the chain of if/else statements allows having an equivalent of switch in many cases (but not all). An important feature of switch is that all options are selected (identified) based on the integer expression value, usually a variable. + +In general case, the switch statement looks as follows: + +``` +switch ( expression ) +{ +   case constant-expression : statements [break; ] +   ... +   [ default : statements ]  +} + +``` + +The statement header starts with the keyword switch. It must be followed by an expression in parentheses. The block with curly brackets is also required. + +Integer values that can be obtained by evaluating an expression should be specified as constants after the case keyword. A constant is a literal of any [integer types](/en/book/basis/builtin_types/integer_numbers), for example, int (10, 123), ushort (characters 'A', 's', '*' etc.), or [enum](/en/book/basis/builtin_types/enums) elements. Real numbers, variables, or expressions are not allowed here. + +There may be many such case options, or may not be at all, which is indicated by semicircular brackets with index opt(n). All variants must have unique constants (no repetitions). + +For each alternative declared with case, a statement must be written after the colon, which will be executed if the value of the expression is equal to the corresponding constant. Again, a statement can be simple or compound. In addition, it is permissible to write several simple statements without enclosing them in curly brackets: they will still be executed as a group (a compound statement). + +One or more of these statements can be followed by the [break](/en/book/basis/statements/statements_break) jump statement. + +If there is a break, after executing the previous statements from the case branch, the switch statement exits, i.e., control is transferred to the statements below switch. + +In the absence of break, the statements of the next branch or several branches case continue to be executed, that is, until the first encountered break or the end of the block switch. This is called "fall-through". + +Thus, the switch statement not only allows splitting the algorithm execution flow into several alternatives but also combining them, which is not available for the if operator. On the other hand, in the switch statement, unlike if, you cannot select a range of values as a condition for activating alternatives. + +The default keyword allows you to set the default algorithm variant, that is, for any other expression values except for constants from all cases. The default option may not be present, or there must be only one. + +The sequence in which case constants and default are listed can be arbitrary. + +Even if there is no algorithm for the default branch yet, it is recommended to make it explicitly empty, i.e. containing break. An empty default will remind you and other programmers that other options exist but are considered unimportant because otherwise, the default branch would have to signal an error. + +Several case variants with different constants can be listed one below the other (or left to right) without statements, but the last one must have a statement. Such combined cases are indicated on the diagram by the index (i). + +Here is the simplest and most useless switch: + +``` +switch(0) +{ +} + +``` + +Let's consider a more complex example with different modes (StmtSelectionSwitch.mq5). In it, the switch operator is placed inside the loop to show how its work depends on the values of the control variable i. + +``` +for(int i = 0; i < 7; i++) +{ +   double factor = 1.0; +    +   switch(i) +   { +      case -1: +         Print("-1: Never hit"); +         break; +      case 1: +         Print("Case 1"); +         factor = 1.5; +         break; +      case 2: // fall-through, no break (!) +         Print("Case 2"); +         factor *= 2; +      case 3: // same statements for 3 and 4 +      case 4: +         Print("Case 3 & 4"); +         { +            double local_var = i * i; +            factor *= local_var; +         } +         break; +      case 5: +         Print("Case 5"); +         factor = 100; +         break; +      default: +         Print("Default: ", i); +   } +    +   Print(factor); +} + +``` + +The -1 option will fail because the loop changes the variable i from 0 to 6 (inclusive). When i is 0, the default branch will trigger. It will also take control when i is equal to 6. All other possible i values are distributed according to the corresponding case directives. At the same time, there is no break statement after case 2, and therefore the code for options 3 and 4 will be executed in addition to 2 (in such cases, it is always recommended to leave a comment that this was done intentionally). + +Cases 3 and 4 have a common statement block. But it is also important to note here that if you want to declare a local variable inside one of the case options, you need to enclose the statements in a nested compound block ('{...}'). Here, the variable local_varis defined this way. + +It is worth advising that in the default case, there is no break statement. It's redundant because default is written last in this case. However, many programmers advise inserting break at the end of any option, even the last one, because it can cease to be the last in the process of subsequent modifications of the code, and then it is easy to forget to add break, which will probably lead to an error in the program logic. + +If in switch there is no default, and the header expression does not match any of the case constants, the entire switch is skipped. + +As a result of the script execution, we will receive the following messages in the log: + +``` +Default: 0 +1.0 +Case 1 +1.5 +Case 2 +Case 3 & 4 +8.0 +Case 3 & 4 +9.0 +Case 3 & 4 +16.0 +Case 5 +100.0 +Default: 6 +1.0 + +``` diff --git a/skills/mql5/references/book/01-basis/0067-basis-statements-statements-break.md b/skills/mql5/references/book/01-basis/0067-basis-statements-statements-break.md new file mode 100644 index 0000000..2db4680 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0067-basis-statements-statements-break.md @@ -0,0 +1,107 @@ +# Break jump + +The break operator is intended for early termination of the for, while, do loops, as well as exit from the switch selection statement. The operator can only be applied within the specified statements and only affects the one immediately containing break if there are multiple nested ones. After processing the break statement, program execution continues to the statement following the interrupted loop or switch. + +The syntax is very simple: the keyword break and a semicolon: + +``` +break ; + +``` + +When used inside loops, break is usually implemented in one of the branches of the [if/else](/en/book/basis/statements/statements_if) conditional operator. + +Consider a script that prints the current system time counter once per second, but no more than 100 times. It provides for handling the interruption of the process by the user: for this, the function IsStopped is polled in the conditional operator if and its dependent statement contains break (StmtJumpBreak.mq5). + +``` +int count = 0; +while(++count < 100) +{ +   Comment(GetTickCount()); +   Sleep(1000); +   if(IsStopped()) +   { +      Print("Terminated by user"); +      break; +   } +} + +``` + +In the following example, a diagonal matrix is filled in with a times table (the top right corner will remain filled with zeros). + +``` +int a[10][10] = {0}; +for(int i = 0; i < 10; ++i) +{ +   for(int j = 0; j < 10; ++j) +   { +      if(j > i) +         break; +      a[i][j] = (i + 1) * (j + 1); +   } +} +ArrayPrint(a); + +``` + +When the inner loop variable j is greater than the outer loop variable i, the break statement breaks the inner loop. Of course, this is not the best way to fill the matrix diagonally: it would be easier to loop over j from 0 to i without any break, but here it demonstrates the presence of equivalent constructions with break and without break. + +Although things may not be so obvious in production projects, it is recommended to avoid the break operator whenever possible and replace it with additional variables (for example, a boolean variable with a "telling" name needAbreak), which should be used in terminal expressions in loop headers to break them in the standard way. + +Imagine that two nested loops are used to find duplicate characters in a string. The first loop sequentially makes each character of the string current and the second runs through the remaining (to the right) characters. + +``` +string s = "Hello, " + Symbol(); +ushort d = 0; +const int n = StringLen(s); +for(int i = 0; i < n; ++i) +{ +   for(int j = i + 1; j < n; ++j) +   { +      if(s[i] == s[j]) +      { +         d = s[i]; +         break; +      } +   } +} + +``` + +If the characters at positions i and j match, remember the duplicate character and exit the loop via break. + +It could be assumed that the variable d should contain the letter 'l' after the execution of this fragment. However, if you place the script on the most popular instrument "EURUSD", the answer will be 'U'. The thing is that break breaks only the inner loop, and after finding the first duplicate ('ll' in the word "Hello"), the loop continues on i. Therefore, to exit from several nested loops at once, additional measures must be taken. + +The most popular way is to include in the condition of the outer loop (or all outer loops) a variable that is filled in the inner loop. In our case, there is already such a variable: d. + +``` +for(int i = 0; i < n && d == 0; ++i) +{ +   for(int j = i + 1; j < n; ++j) +   { +      if(s[i] == s[j]) +      { +         d = s[i]; +         break; +      } +   } +} + +``` + +Checking d for being equal to 0 will now stop the outer loop after finding the first duplicate. But the same check can be added to the inner loop, which eliminates the need to use break. + +``` +for(int i = 0; i < n && d == 0; ++i) +{ +   for(int j = i + 1; j < n && d == 0; ++j) +   { +      if(s[i] == s[j]) +      { +         d = s[i]; +      } +   } +} + +``` diff --git a/skills/mql5/references/book/01-basis/0068-basis-statements-statements-continue.md b/skills/mql5/references/book/01-basis/0068-basis-statements-statements-continue.md new file mode 100644 index 0000000..1fed455 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0068-basis-statements-statements-continue.md @@ -0,0 +1,58 @@ +# Continue jump + +The continue statement breaks the current iteration of the innermost loop containing continue and initiates the next iteration. The statement can only be used inside for, while and do loops. Execution of continue inside for results in the next calculation of the expression in the loop header (increment/decrement of the loop variable), after which the loop continuation condition is checked. Executing continue inside while or do immediately results in checking the condition in the loop header. + +The statement consists of the keyword continue and a semicolon: + +``` +continue ; + +``` + +It is usually placed in one of the branches of the [if/else](/en/book/basis/statements/statements_if) or [switch](/en/book/basis/statements/statements_switch) conditional statement. + +For example, we can generate a times table with gaps: when the product of two indexes is odd, the corresponding array element will remain zero (StmtJumpContinue.mq5). + +``` +int a[10][10] = {0}; +for(int i = 0; i < 10; ++i) +{ +   for(int j = 0; j < 10; ++j) +   { +      if((j * i) % 2 == 1) +         continue; +      a[i][j] = (i + 1) * (j + 1); +   } +} +ArrayPrint(a); + +``` + +And here's how you can calculate the sum of the positive elements of an array. + +``` +int b[10] = {1, -2, 3, 4, -5, -6, 7, 8, -9, 10}; +int sum = 0; +for(int i = 0; i < 10; ++i) +{ +   if(b[i] < 0) continue; +   sum += b[i]; +} +Print(sum); // 33 + +``` + +Note that the same loop can be rewritten without continue but with a greater nesting of code blocks: + +``` +for(int i = 0; i < 10; ++i) +{ +   if(b[i] >= 0) +   { +      sum += b[i]; +   } +} + +``` + +Thus, operator continue is often used to simplify code formatting (especially if there are several conditions to pass). However, which of the two approaches to choose is a matter of personal preference. diff --git a/skills/mql5/references/book/01-basis/0069-basis-statements-statements-return.md b/skills/mql5/references/book/01-basis/0069-basis-statements-statements-return.md new file mode 100644 index 0000000..f751982 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0069-basis-statements-statements-return.md @@ -0,0 +1,47 @@ +# Return jump + +The return operator is designed to return control from [functions](/en/book/basis/functions). Given that all executable statements are inside a particular function, it can be indirectly used to interrupt containing it loops for, while, and do of any nesting level. It should be taken into account that unlike continue and, especially, break, all statements following interrupted loops inside the function will also be ignored. + +The syntax for the return operator: + +``` +return ([expression]) ; + +``` + +The need to specify an expression is determined by the function signature (more on this will be discussed in the [relevant section](/en/book/basis/functions/functions_return)). For a general understanding of how return works in the context of control statements, let's view an example with the main script function OnStart. Since it is of type void, i.e. it does not return anything, the operator takes the following form: + +``` +return ; + +``` + +In the section on [break](/en/book/basis/statements/statements_break), we implemented an algorithm for finding duplicate characters in a string. To break two nested loops, we not only use break but also modify the condition of the outer loop. + +With the return operator, this can be done in a simpler way (StmtJumpReturn.mq5). + +``` +void OnStart() +{ +   string s = "Hello, " + Symbol(); +   const int n = StringLen(s); +   for(int i = 0; i < n; ++i) +   { +      for(int j = i + 1; j < n; ++j) +      { +         if(s[i] == s[j]) +         { +            PrintFormat("Duplicate: %c", s[i]); +            return; +         } +      } +   } +    +   Print("No duplicates"); +} + +``` + +If equality is found in the if operator, we display the symbol and exit the function. If this algorithm was in a custom function other than OnStart, we could define a return type for it (for example, ushort instead of void) and pass the found character using the full form return to the calling code. + +Since the double letter 'l' is known to exist in the test string, the statement after the loops (Print) will not be executed. diff --git a/skills/mql5/references/book/01-basis/0070-basis-statements-statements-null.md b/skills/mql5/references/book/01-basis/0070-basis-statements-statements-null.md new file mode 100644 index 0000000..c6b9e80 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0070-basis-statements-statements-null.md @@ -0,0 +1,35 @@ +# Empty statement + +The empty statement is the simplest in the language. It consists of only one character, the semicolon ';' + +An empty statement is used in the program in those places where the syntax requires the presence of a statement, but the logic of the algorithm instructs to do nothing. + +For example, the following while loop is used to find a space in a string. The whole essence of the algorithm is performed directly in the loop header, so its body must be empty. We could write an empty block of curly brackets, but an empty statement would also work here. (StmtNull.mq5). + +``` +int i = 0; +ushort c; +string s = "Hello, " + Symbol(); +while((c = s[i++]) != ' ' && c != 0); // intentional ';' (!) +if(c == ' ') +{ +   Print("Space found at: ", i); +} + +``` + +Note that if the semicolon at the end of the while header is omitted (perhaps by accident), then the if statement will be treated as the body of the loop. As a result, there will be no output to the log by the Print function. In fact, the program will not work correctly, although without noticeable errors. + +The opposite situation is also possible: an extra semicolon after the loop header (where it should not have been) will "detach" the loop body from the header, i.e. only an empty statement will be executed in the loop. + +In this regard, optional semicolons should be checked in the code, and wherever they are placed intentionally, leave a comment with explanations. + +By the way, from a formal point of view, the empty statement is also used in the [for](/en/book/basis/statements/statements_for) statement when we omit the initialization expression. In fact, there is always initialization: + +``` +for ( [initialization] ; [end loop condition]; [post-expression] ) +  loop body + +``` + +The first character ';' is part of an initialization statement, which can be an expression or an empty statement: both contain the character ';' at the end, with the latter containing nothing but ';'. Thus, optionality (emptiness) is achieved. diff --git a/skills/mql5/references/book/01-basis/0071-basis-functions.md b/skills/mql5/references/book/01-basis/0071-basis-functions.md new file mode 100644 index 0000000..20f234b --- /dev/null +++ b/skills/mql5/references/book/01-basis/0071-basis-functions.md @@ -0,0 +1,11 @@ +# Functions + +A function is a named block with statements. Almost the entire application algorithm of the program is contained in functions. Outside of functions, only auxiliary operations are performed, such as creating and deleting global variables. + +The execution of statements within a function occurs when we call that function. Some functions, the main ones, are called automatically by the terminal when various events occur. They are also referred to as the MQL program entry points or event handlers. In particular, we already know that when we run a script on a chart, the terminal calls its main function OnStart. In other types of programs, there are other functions called by the terminal, which we will discuss in detail in the [fifth](/en/book/applications) and [sixth](/en/book/automation) chapters covering the trading architecture of the MQL5 API. + +In this chapter, we will learn how to define and declare a function, how to describe and pass parameters to it, and how to return the result of its work from the function. + +We will also talk about function overloading, i.e., the ability to provide multiple functions with the same name, and how this can be useful. + +Finally, we will get acquainted with a new type: a pointer to a function. diff --git a/skills/mql5/references/book/01-basis/0072-basis-functions-functions-definition.md b/skills/mql5/references/book/01-basis/0072-basis-functions-functions-definition.md new file mode 100644 index 0000000..aecbe72 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0072-basis-functions-functions-definition.md @@ -0,0 +1,65 @@ +# Function definition + +A function definition consists of the value type it returns, an identifier, a list of parameters in parentheses, and a body — a block of code with statements. Parameters in the list are separated by commas. Each parameter is given a type, a name, and optionally a default value. + +``` +result_type function_identifier ( [parameter_type parameter_identifier +                                       = value_by_default] ,... ) +{ +  [statement] +   ... +} + +``` + +It is allowed to create functions without parameters: then there is no list, and empty brackets are placed after the function name (they cannot be omitted). Optionally, you can write the void keyword between the brackets to emphasize that there are no parameters. For example, like this: + +``` +void OnStart(void) +{ +} + +``` + +The combination of return type, number and types of parameters in the list is called a function prototype or signature. Different functions can have the same prototype. + +In previous sections, we have already seen function definitions such as OnStart and Greeting. Now let's try to implement the calculation of Fibonacci numbers as a test function. These numbers are calculated by the following formula: + +``` +f[0] = 1 +f[1] = 1 +f[i] = f[i - 1] + f[i - 2], i > 1 + +``` + +The first two numbers are 1, and all subsequent numbers are the sum of the previous two. We give the beginning of the series: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55... + +You can calculate the number at a given index using the following function (FuncFibo.mq5). + +``` +int Fibo(const int n) +{ +   int prev = 0; +   int result = 1; +   for(int i = 0; i < n; ++i) +   { +      int temp = result; +      result = result + prev; +      prev = temp; +   } +   return result; +} + +``` + +It takes one parameter n of type int and returns a result of type int. The n parameter has the const modifier because we are not going to change n inside the function (such an explicit declaration of restrictions on the "rights" of variables is welcome because it helps avoid random errors). + +Local variables prev and result will store the current values of the last two numbers in the series. In the loop over i we calculate their sum, getting the next number of the sequence. Previously, the old value result is written to the variable temp, so that after summation, it is transferred to prev. + +After executing the loop a given number of times, the result variable contains the desired number. We return it from the function using the result statement. + +The input parameter of a function is also a local variable that will be initialized to the actual value during the function call. This value is passed "outside" from the statement with the function call. + +Parameter names must be unique and must not match local variable names. + +The body of a function is a block of code that defines the [scope and lifetime of local variables](/en/book/basis/variables/scope_and_lifetime). Their definition and operation principles were discussed in the sections [Declaration/definition statements](/en/book/basis/statements/statements_declaration) and [Initialization](/en/book/basis/variables/initialization). diff --git a/skills/mql5/references/book/01-basis/0073-basis-functions-functions-call.md b/skills/mql5/references/book/01-basis/0073-basis-functions-functions-call.md new file mode 100644 index 0000000..4c414ed --- /dev/null +++ b/skills/mql5/references/book/01-basis/0073-basis-functions-functions-call.md @@ -0,0 +1,29 @@ +# Function call + +A function is called when its name is mentioned in an expression. After the name, there should be a pair of parentheses, in which the arguments corresponding to the function parameters (if there is a list of parameters in its definition) are indicated, separated by commas. + +A little later, we will look at the [function pointer](/en/book/basis/functions/functions_typedef) type, which allows you to create variables that point to a function with specific characteristics, and then call it not by name, but through this variable. + +Continuing the example with the Fibo function, let's call it from the OnStart function. To do this, let's create a variable f to store the resulting number and in its initialization expression we indicate the name of the function Fibo and an integer (for example, 10) as an argument, in parentheses. + +``` +void OnStart() +{ +   int f = Fibo(10);  +   Print(f); // 89 +} + +``` + +We are not required to create a variable to receive a value from a function. Instead, you can call the function directly from an expression, such as "2*Fibo(10)" or "Print(Fibo(10))". Then its value will be substituted into the expression at the place of the call. Here, the auxiliary variable f is introduced to implement the call and return of a value in a separate statement. + +The call process includes the following steps: + +- Execution of the statement sequence of the calling function (OnStart) is suspended; +- The value of the argument gets into the input parameter n of the called function (Fibo); +- The execution of its statements starts; +- When it is completely finished, it sends the result back (remember the return statement inside); +- The result is written to the variable f; and +- After that, the execution of the OnStart function continues, that is, the number is printed to the log (Print). + +For each function call, the compiler generates auxiliary binary code (the programmer does not need to worry about it). The idea of this code is that before calling the function, it pushes the current position in the program onto the stack, and after the call is completed, it retrieves it and uses it to return to the statements following the function call. When one function calls another, that one calls one more function, the second calls a third, and so on, the return addresses of transitions throughout the hierarchy of called functions are accumulated on the stack (hence the name stack). As nested function calls are processed, the stack will be cleared in reverse order. Note that the stack also allocates memory for the local variables of each function. diff --git a/skills/mql5/references/book/01-basis/0074-basis-functions-functions-parameters.md b/skills/mql5/references/book/01-basis/0074-basis-functions-functions-parameters.md new file mode 100644 index 0000000..795279e --- /dev/null +++ b/skills/mql5/references/book/01-basis/0074-basis-functions-functions-parameters.md @@ -0,0 +1,35 @@ +# Parameters and arguments + +The arguments passed to the function with its call are the initial values of the corresponding function parameters. The number, order, and types of arguments must match the function prototype. However, the order in which arguments are computed is not defined (see the [Basic concepts](/en/book/basis/expressions/expressions_overview) section). Depending on the specifics of the source code and optimization considerations, the compiler may choose an option that is convenient for it. For example, given a list of two arguments, the compiler might evaluate the second argument first and then the first. It is only guaranteed that both arguments will be evaluated before the call. + +Each argument is mapped to the corresponding parameter in the same way that [variables are initialized](/en/book/basis/variables/initialization), with [implicit casts](/en/book/basis/conversion) if necessary. Before the function starts, all its parameters are guaranteed to have the specified values. For example, depending on the arguments passed, calls to the Fibo function can lead to the following effects (described in the comments): + +``` +// warnings +double d = 5.5; +Fibo(d);          // possible loss of data due to type conversion +Fibo(5.5);        // truncation of constant value +Fibo("10");       // implicit conversion from 'string' to 'number' +// errors +Fibo();           // wrong parameters count +Fibo(0, 10);      // wrong parameters count + +``` + +All warnings are about implicit conversions that the compiler performs because the value types do not match the parameter types. They should be regarded as potential errors and eliminated. The "wrong parameters count" error occurs when there are too few or too many arguments. + +In theory, a function parameter does not have to have a name, i.e. the type alone is sufficient to describe the parameter. This sounds rather strange because we will not be able to access a parameter without a name inside the function. However, when creating programs based on some standard interfaces, sometimes you have to write functions that must correspond to given prototypes. In this case, some parameters inside the function may be unnecessary. Then, to explicitly indicate this fact, the programmer can omit their names. For example, the MQL5 API requires the implementation of the [OnDeinit](/en/book/applications/runtime/runtime_oninit_ondeinit) event handler function with the following prototype: + +``` +void OnDeinit(const int reason); + +``` + +If we don't need the reason parameter in the function code, we can omit it in the description: + +``` +void OnDeinit(const int); + +``` + +The terminal event handling function is usually called by the terminal itself, but if we needed to call a similar function (with an anonymous parameter) from our code, then we need to pass all the arguments, regardless of whether the parameters are named or not. diff --git a/skills/mql5/references/book/01-basis/0075-basis-functions-functions-ref-value.md b/skills/mql5/references/book/01-basis/0075-basis-functions-functions-ref-value.md new file mode 100644 index 0000000..267a9f0 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0075-basis-functions-functions-ref-value.md @@ -0,0 +1,117 @@ +# Value parameters and reference parameters + +Arguments can be passed to a function in two ways: by value and by reference. + +All the cases we've looked at so far are passing by value. This option means that the value of the argument prepared by the calling code snippet is copied into a new variable, the corresponding input variable of the function. Otherwise, the argument and input variable are unrelated. All subsequent manipulations with the variable inside the function do not affect the argument in any way. + +To describe a reference parameter, add an ampersand sign '&' on the right of the type. Many programmers prefer to append an ampersand to a parameter name, thus emphasizing that the parameter is a reference to the given type. For example, the following entries are equivalent: + +``` +void func(int ¶meter); +void func(int & parameter);  +void func(int& parameter); + +``` + +When a function is called, a corresponding local variable is not created for a reference parameter. Instead, the argument specified for this parameter becomes available inside the function under the name (alias) of the input parameter. Thus, the value is not copied, but used at the same address in memory. Therefore, modifications to a parameter within a function are reflected in the state of its associated argument. An important feature follows from this. + +You can only specify a variable (LValue, see [Assignment operator](/en/book/basis/expressions/operator_assignment)) as an argument for a reference parameter. Otherwise, we'll get the "parameter passed as reference, variable expected" error. + +Passing by reference is used in several cases: + +- to improve the efficiency of the program by eliminating the copying of the value; +- to pass modified data from a function to the calling code when returning a single value with return is not enough; + +The first point is especially relevant for potentially large variables such as strings or arrays. + +To distinguish between the first and second purposes of a reference parameter, the authors of the function are encouraged to add the const modifier when the parameter inside the function is not expected to change. This will remind you and make it clear to other developers that passing a variable inside a function will not lead to side effects. + +Not applying the const modifier to reference parameters where possible can lead to problems throughout the entire function call hierarchy. The fact is that calling such functions will require non-constant arguments. Otherwise, the error "constant variable cannot be passed as reference" will occur. As a result, it may gradually turn out that all parameters in all functions should be stripped of the const modifier for the sake of the code compilability. In fact, this actually expands the scope for potential bugs with unintentional corruption of variables. The situation should be corrected in the opposite way: put const wherever return and modification of values are not required. + +To compare the ways of passing parameters in the FuncDeclaration.mq5 script, several functions are implemented: FuncByValue – passing by value, FuncByReference – passing by reference, FuncByConstReference – passing by constant reference. + +``` +void FuncByValue(int v) +{ +   ++v; +   // we are doing something else with v +} +  +void FuncByReference(int &v) +{ +   ++v; +} +  +void FuncByConstReference(const int &v) +{ +   // error +   // ++v; // 'v' - constant cannot be modified +   Print(v);  +} + +``` + +In the OnStart function, we call all these functions and observe their effect on i variable used as an argument. Note that passing a parameter by reference does not change the function call syntax. + +``` +void OnStart() +{ +   int i = 0; +   FuncByValue(i);          // i cannot change +   Print(i);                // 0 +   FuncByReference(i);      // i is changing +   Print(i);                // 1 +   FuncByConstReference(i); // i cannot change, 1 +   const int j = 1; +   // error +   // 'j' - constant variable cannot be passed as a reference +   // FuncByReference(j); +    +   FuncByValue(10);         // ok +   // error: '10' - parameter passed as reference, variable expected +   // FuncByReference(10); +} + +``` + +The literal can only be passed to FuncByValue function, since other functions require a reference, i.e. a variable, as an argument. + +Function FuncByReference cannot be called with the variable j, since the latter is declared as a constant, and this function declares the ability (or intention) to change its parameter since it is not equipped with the const modifier. This generates the "constant variable cannot be passed as reference" error. + +The script also describes the Transpose function: it transposes a 2x2 matrix passed as a two-dimensional array by reference. + +``` +void Transpose(double &m[][2]) +{ +   double temp = m[1][0]; +   m[1][0] = m[0][1]; +   m[0][1] = temp; +} + +``` + +Its call from OnStart demonstrates the expected change in the contents of the local array a. + +``` +double a[2][2] = {{-1, 2}, {3, 0}}; +Transpose(a); +ArrayPrint(a); + +``` + +In MQL5, array parameters are always passed as an internal structure of a dynamic array (see the [Characteristics of arrays](/en/book/basis/arrays/arrays_overview) section). As a consequence, the description of such a parameter must necessarily have an open size in the first dimension, that is, it is empty inside the first pair of square brackets. + +This does not prevent, if necessary, passing to the function the actual argument, which is an array with a fixed size (as in our example). However, functions like [ArrayResize](/en/book/common/arrays/arrays_dynamic) will not be able to resize or otherwise reorganize such a masked fixed array. + +The sizes of the array in all dimensions except the first must match for both, the parameter and argument. Otherwise, we will get a "parameter conversion not allowed" error. In particular, the TransposeVectorfunction is defined in the example: + +``` +void TransposeVector(double &v[]) +{ +} + +``` + +An attempt to call it on a two-dimensional array a is commented out in OnStart because it generates the above error: array dimensions do not match. + +In addition to passing parameters by value or by reference, there is another option: passing a pointer. Unlike C++, MQL5 only supports [pointers](/en/book/oop/classes_and_interfaces/classes_pointers) for object types ([classes](/en/book/oop/classes_and_interfaces)). We will look at this feature in the third Part. diff --git a/skills/mql5/references/book/01-basis/0076-basis-functions-functions-parameters-default.md b/skills/mql5/references/book/01-basis/0076-basis-functions-functions-parameters-default.md new file mode 100644 index 0000000..e6d186c --- /dev/null +++ b/skills/mql5/references/book/01-basis/0076-basis-functions-functions-parameters-default.md @@ -0,0 +1,46 @@ +# Optional parameters + +MQL5 provides an opportunity to specify default values for parameters when describing a function. For this, the [initialization](/en/book/basis/variables/initialization) syntax is used, that is, a literal of the corresponding type to the right of the parameter, after the '=' sign. For example: + +``` +void function(int value = 0); + +``` + +When calling a function, arguments for such parameters can be omitted. Then their values will be set to their default values. Such parameters are called optional (optional). + +Optional parameters must appear at the end of the parameter list. In other words, if the i-th parameter is declared with initialization, then all subsequent parameters must also have it. Otherwise, a compilation error "missing default value for parameter" is shown. Below is a description of a function with such a problem. + +``` +double Largest(const double v1, const double v2 = -DBL_MAX, +               const double v3); + +``` + +There are two solutions: either the parameter v3 must also have a default value, or the parameter v2 must become mandatory. + +You can only omit optional arguments when calling a function from right to left. That is, if the function has two parameters and both are optional, then when calling, you cannot skip the first one, but specify the second one. The single value passed will be matched against the first parameter, and the second will be considered omitted. If both arguments are missing, the empty parentheses are still needed. + +Consider the function of finding the maximum number of three. The first parameter is mandatory, the last two are optional and equal by default to the minimum possible number of type double. Thus, each of them, in the absence of an explicitly passed value, will certainly be less than (or, in extreme cases, equal to) all other parameters. + +``` +double Largest(const double v1, const double v2 = -DBL_MAX, +               const double v3 = -DBL_MAX) +{ +   return v1 > v2 ? (v1 > v3 ? v1 : v3) : (v2 > v3 ? v2 : v3); +} + +``` + +This is how you can call it: + +``` +Print(Largest(1));       // ok: 1 +Print(Largest(0, -2));   // ok: 0 +Print(Largest(1, 2, 3)); // ok: 3 + +``` + +With the help of optional parameters, MQL5 implements the concept of functions with a variable number of parameters in custom functions. + +MQL5 does not support the ellipsis syntax for defining functions with a variable number of parameters, as C++ does. At the same time, there are built-in functions in the MQL5 API, which are described using ellipsis and accept a variable number of arbitrary parameters. For example, it is the [Print](/en/book/common/output/output_print) function. Its prototype looks like this: void Print(argument, ...). Therefore, we can call it with up to 64 arguments separated by commas (excluding arrays) and it will display them in the log. diff --git a/skills/mql5/references/book/01-basis/0077-basis-functions-functions-return.md b/skills/mql5/references/book/01-basis/0077-basis-functions-functions-return.md new file mode 100644 index 0000000..e7a8e76 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0077-basis-functions-functions-return.md @@ -0,0 +1,60 @@ +# Return values + +Functions can return the values of built-in types, [structures](/en/book/oop/structs_and_unions) with fields of built-in types, as well as [pointers to functions](/en/book/basis/functions/functions_typedef) and pointers to [class](/en/book/oop/classes_and_interfaces) objects. The type name is written in the function definition before the name. If the function does not return anything, it should be assigned the void type. + +To return from an array function, you must use parameters passed by reference (see [Value parameters and reference parameters](/en/book/basis/functions/functions_ref_value)). + +A value is returned using the [return](/en/book/basis/statements/statements_return) statement, in which an expression is specified after the return keyword. Any of the two forms may be used: + +``` +return expression ; + +``` + +or: + +``` +return ( expression ) ; + +``` + +If the function is of type void, then the return statement is simplified: + +``` +return ; + +``` + +The return statement cannot contain any expression inside the void-function: the compiler will generate an error "'return' - 'void' function returns a value". + +For such functions, theoretically, it is not necessary to use return at the end of the block with the function body. We saw this in the example of the OnStart function. + +If the function has a type other than void, then the return statement must be mandatory. If it is not present, a compilation error "not all control paths return a value" will occur. + +``` +int func(void) +{ +   if(IsStopped()) return; // error: function must return a value +                           // error: not all control paths return a value   +} + +``` + +It is important to note that a function body can have multiple return statements. In particular, in case of early exits by condition. Any return statement breaks the execution of the function at the place where it is located. + +If a function must return a value (because it is not of type void), and it is not specified in the return operator, the compiler will generate an error "function must return a value". The compiler-correct version of the func function is given below (FuncReturn.mq5). + +``` +int func(void) +{ +   if(IsStopped()) return 0; +   return 1; +} + +``` + +If the return value differs from the specified function type, the compiler will attempt an [implicit conversion](/en/book/basis/conversion/conversion_implicit). In case the types require explicit conversion, an error will be generated. + +To return a value, a temporary variable is implicitly created and made available to the calling code. + +After we learn about object types (see the chapter on [Classes](/en/book/oop/classes_and_interfaces)) and the ability to return pointers to objects from functions, we'll get back to considering how to pass them safely. Unlike C++, functions in MQL5 are not capable of returning references. Attempting to declare a function with an ampersand in the result type results in a "'&' - reference cannot used" error. diff --git a/skills/mql5/references/book/01-basis/0078-basis-functions-functions-declaration.md b/skills/mql5/references/book/01-basis/0078-basis-functions-functions-declaration.md new file mode 100644 index 0000000..b82b82f --- /dev/null +++ b/skills/mql5/references/book/01-basis/0078-basis-functions-functions-declaration.md @@ -0,0 +1,40 @@ +# Function declaration + +Function declaration describes a prototype without specifying a function body. Instead of a block with a body, a semicolon is put. + +The declaration is necessary for the compiler so that it can check in subsequent code fragments how correctly the function is called by name, passing arguments to it and getting the result. + +The entire function definition (including the body) is also a declaration, so there is no need to declare a function in addition to the definition. + +For example, the declaration of the Fibo function above could look like this. + +``` +int Fibo(const int n); + +``` + +Separate function declarations and definitions are used when building a program from several files with source text: then the declaration is made in the header file with the extension mqh (see the section about the [#include preprocessor directive ](/en/book/basis/preprocessor/preprocessor_include)), which is included in files where the function is used, and the function definition is implemented in only one of the files. Matching of the function signature in the declaration and definition provides error protection. In other words, a single declaration guarantees the consistency of changes made to the entire source code + +If we declare a function and call it somewhere in the code, but do not provide a fully appropriate definition for it, the compiler will throw an error: "function 'Name' must have a body". This often happens when there are typos or inaccuracies either in the declaration or in the definition, as well as in the process of changing the source codes, when some of the corrections have already been made, and the other part has most likely been forgotten. + +If the function is declared and not used anywhere, the compiler does not require its definition either - such an element is simply "cut out" from the binary program. + +In the [Declaration/definition statements](/en/book/basis/statements/statements_declaration) section, we considered an example of the Init function (script StmtDeclaration.mq5), which was used to initialize variables. There, in particular, the problem was demonstrated that the global variable k cannot be defined before the Init function, since the initial value k is obtained by calling Init. The compiler through the error "'Init' is an unknown identifier". + +Now we know that such a problem can be solved with a declaration. In the FuncDeclaration.mq5 script, we added the following forward declaration of the Init function before the k variable, and left the Init definition after k. + +``` +// preliminary declaration +int Init(const int v); +// before adding preliminary declaration above +// here was an error: 'Init' is an unknown identifier +int k = Init(-1); +int Init(const int v) +{ +   Print("Init: ", v); +   return v; +} + +``` + +Now the script compiles normally. Technically, in this case, we could simply move the function above the variable without a preliminary declaration. We did this to explain the concept. However, there are cases of mutual dependence of language elements on each other (for example, classes), when it is impossible to go without a preliminary declaration within the same file. diff --git a/skills/mql5/references/book/01-basis/0079-basis-functions-functions-recursive.md b/skills/mql5/references/book/01-basis/0079-basis-functions-functions-recursive.md new file mode 100644 index 0000000..0063ba2 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0079-basis-functions-functions-recursive.md @@ -0,0 +1,29 @@ +# Recursion + +It is allowed to call the same function from statements inside a function. Such calls are called recursive. + +Let's go back to the example of calculating Fibonacci numbers. Following the formula for calculating each number as the sum of the previous two (except for the first two, which are equal to 1), it is easy to write a recursive function for calculating Fibonacci numbers. + +``` +int Fibo(const int n) +{ +   if(n <= 1) return 1; +    +   return Fibo(n - 1) + Fibo(n - 2); +} + +``` + +A recursive function must be able to return control without recursion, as in our case inside the conditional statement if for indexes 0 and 1. Otherwise, the sequence of function calls could continue indefinitely. In practice, because unfinished function calls accumulate in a limited area of ​​memory called the stack (see the [Declaration/Definition statements](/en/book/basis/statements/statements_declaration) section, and the "Heap" and "Stack" sidebar in the [Describing arrays](/en/book/basis/arrays/arrays_declaration) section), sooner or later the function will terminate with the "Stack overflow" runtime error. This problem is shown in the FiboEndless function. + +``` +int FiboEndless(const int n) +{ +   return FiboEndless(n - 1) + FiboEndless(n - 2); +} + +``` + +Please note that this is not a compilation error. In such a case, the compiler will not even generate a warning (although, technically it could). The error occurs during script execution. It will be printed to the Experts journal in the terminal. + +Recursion can occur not only when a function is called from the function itself. For example, if the F function calls the G function which, in turn, calls the F function, this case is an indirect recursion. Thus, recursion can occur as a result of cyclic calls of any depth. diff --git a/skills/mql5/references/book/01-basis/0080-basis-functions-functions-overloading.md b/skills/mql5/references/book/01-basis/0080-basis-functions-functions-overloading.md new file mode 100644 index 0000000..ac26b05 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0080-basis-functions-functions-overloading.md @@ -0,0 +1,131 @@ +# Function overloading + +MQL5 allows the definition of functions with the same name but with different numbers or types of parameters in the same source code. This approach is called function overloading. It is usually applied when the same action can be triggered by different inputs. Differences in signatures allow the compiler to automatically determine which function to call based on the arguments passed. But there are some specifics. + +Functions cannot differ only in their return type. In this case. the overload mechanism is not triggered and the "function already defined and has different type" error is returned. + +If functions of the same name have different numbers of parameters and the "extra" parameters are declared optional, then the compiler will not be able to determine which one to call. This will generate the error "ambiguous call to overloaded function with the same parameters". + +When an overloaded function is called, the compiler matches the arguments and parameters in the available overloads. If no exact match is found, the compiler tries to add/remove the const modifier and to perform numeric type expansion and [arithmetic conversion](/en/book/basis/conversion/conversion_arithmetic). In the case of [object pointers](/en/book/oop/classes_and_interfaces/classes_pointers), class inheritance rules are used. + +With a different number of parameters or unrelated parameter types in the same position (such as a number and a string), the choice is usually clear. However, if the parameter types are to be implicitly converted from one to another, ambiguity may arise. + +For example, we have two summation functions: + +``` +double sum(double v1, double v2) +{ +   return v1 + v2; +} +  +int sum(int v1, int v2) +{ +   return v1 + v2; +} + +``` + +Then the following call will result in an error: + +``` +sum(1, 3.14); // overloaded function call is ambiguous + +``` + +Here, the compiler is equally uncomfortable with each of the overloads: for the function double sum(double v1, double v2) it is necessary to implicitly convert the first argument to double, and for int sum(int v1, int v2) the second argument in int needs to be converted. + +The term 'overload' should be interpreted in the sense that a reused name is "loaded" with "duties" several times heavier than a regular name used only for one function. + +Let's try to overload the function for matrix transposition. We already had an example for a 2x2 array (see [Value parameters and reference parameters](/en/book/basis/functions/functions_ref_value)). Let's implement the same operation for a 3x3 array. The size of a multidimensional array parameter in higher dimensions (non-zero) changes the type, i.e. double [][2] is different from double [][3]. Thus, we will overload the old version of the function: + +``` +void Transpose(double &m[][2]); + +``` + +by adding a new one (FuncOverload.mq5): + +``` +void Transpose(double &m[][3]); + +``` + +In the implementation of the new version, it is convenient to use the helper function Swap to exchange two matrix elements at given indices. + +``` +void Transpose(double &m[][3]) +{ +   Swap(m, 0, 1); +   Swap(m, 0, 2); +   Swap(m, 1, 2); +} +  +void Swap(double &m[][3], const int i, const int j) +{ +   static double temp; +    +   temp = m[i][j]; +   m[i][j] = m[j][i]; +   m[j][i] = temp; +} + +``` + +Now we can call both functions from OnStart using the same notation for arrays of different sizes. The compiler itself will generate a call to the correct versions. + +``` +double a[2][2] = {{1, 2}, {3, 4}}; +Transpose(a); +... +double b[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; +Transpose(b); + +``` + +It is important to note that the const modifier on the parameter, although it changes the prototype of the function, is not always a sufficient difference for overloading. Two functions of the same name, which differ only in the presence and absence of const for some parameter, can be considered the same. This will result in a "function already defined and has body" error. This behavior occurs because, for value parameters, the const modifier is discarded when the argument is assigned (because a value parameter, by definition, cannot change the argument in the calling code), and this does not allow one of several overlapped functions to be selected based on it. + +To demonstrate this, it is enough to add a function in the script: + +``` +void Swap(double &m[][3], int i, int j); + +``` + +It is an unsuccessful overload for the existing one: + +``` +void Swap(double &m[][3], const int i, const int j); + +``` + +The only difference between the two functions is the const modifiers for the i and j parameters. Therefore, they are both suitable for calling with arguments of type int and passing by value. + +When parameters are passed by reference, overloading with a difference of only const/non-const attributes succeeds because, for references, the const modifier is important (it changes the type and eliminates the possibility of implicit conversion). This is demonstrated in the script with a couple of functions: + +``` +void SwapByReference(double &m[][3], int &i, int &j) +{ +   Print(__FUNCSIG__); +} +  +void SwapByReference(double &m[][3], const int &i, const int &j) +{ +   Print(__FUNCSIG__); +} +  +void OnStart() +{ +   // ... +   { +      int i = 0, j = 1; +      SwapByReference(b, i, j); +   } +   { +      const int i = 0, j = 1; +      SwapByReference(b, i, j); +   } +} + +``` + +They are left as almost empty stubs, in which the signature of each function is printed using the Print(__FUNCSI__)call. This makes it possible to ensure that the appropriate version of the function is called depending on the const attribute of the arguments. diff --git a/skills/mql5/references/book/01-basis/0081-basis-functions-functions-typedef.md b/skills/mql5/references/book/01-basis/0081-basis-functions-functions-typedef.md new file mode 100644 index 0000000..d3adc7a --- /dev/null +++ b/skills/mql5/references/book/01-basis/0081-basis-functions-functions-typedef.md @@ -0,0 +1,130 @@ +# Function pointers (typedef) + +MQL5 has the typedef keyword, which allows you to describe a special type of function pointer. + +Unlike C++, where typedef has a much wider application, in MQL5 typedef is used only for function pointers. + +The syntax for a new type declaration is: + +``` +typedef function_result_type ( *function_type )( [list_of_input_parameters] ) ; + +``` + +The function_type identifier defines a type name that becomes a synonym (alias) for a pointer to any function that returns a value of the given type function_result_type and accepts a list of input parameters (list_of_input_parameters). + +For example, we can have 2 functions with the same prototypes (two input parameters of type double and the result type is also double) that perform different arithmetic operations: addition and subtraction (FuncTypedef.mq5). + +``` +double plus(double v1, double v2) +{ +   return v1 + v2; +} +  +double minus(double v1, double v2) +{ +   return v1 - v2; +} + +``` + +Their common prototype is easy to describe for use as a pointer: + +``` +typedef double (*Calc)(double, double); + +``` + +This entry introduces the Calc type into the program, with which you can define a variable/parameter for storing/passing a reference to any function with such a prototype, including both functions plus and minus. This type is a pointer because the character '*' (*Calc) is used in the description. We will learn more about the features of the asterisk as applied to pointers when studying OOP. + +It is convenient to use such a class of pointers to create custom algorithms that can "on the fly" call different functions corresponding to the alias, depending on the input data. + +In particular, we can introduce a generalized calculator function: + +``` +double calculator(Calc ptr, double v1, double v2) +{ +   if(ptr == NULL) return 0; +   return ptr(v1, v2); +} + +``` + +Its first parameter is declared with the Calc type. Thanks to this, we can pass an arbitrary function with a suitable prototype to it and, as a result, perform some operation, the essence of which the calculator function itself does not know about. It does this by delegating the call to a pointer: ptr(v1, v2). Because ptr is a function pointer, this syntax not only resembles a function call but actually calls the function that the pointer holds. + +Note that we pre-check the ptr parameter against the special value NULL (NULL is the equivalent of zero for pointers). The fact is that the pointer may not point anywhere, that is, it may not be initialized. So, in the script, we have a global variable described: + +``` +Calc calc; + +``` + +It has no pointers. If it weren't for the "protection" against NULL, calling calculator with an "empty" pointer calc would result in a run-time error "Invalid function pointer call ". + +Calls to the calculator function with different pointers in the first parameter will give the following results (shown in the comments): + +``` +void OnStart() +{ +   Print(calculator(plus, 1, 2));   //  3 +   Print(calculator(minus, 1, 2));  // -1 +   Print(calculator(calc, 1, 2));   //  0 +} + +``` + +Note that if there is no explicit initialization, all function pointers are filled with zero values. This applies to both global and local variables of a given type. + +A pointer type defined with typedef can be returned from functions, for example: + +``` +Calc generator(ushort type) +{ +   switch(type) +   { +      case '+': return plus; +      case '-': return minus; +   } +   return NULL; +} + +``` + +In addition, the type of function pointers is often used for callback functions (callback, see FuncCallback.mq5). Suppose we have a DoMath function that performs lengthy calculations (probably, it is implemented in a separate [library](/en/book/advanced/libraries)). In terms of user interface convenience and friendliness, it would be great to show the user a progress indication. For this purpose, you can define a special type of function pointer for notifications about the percentage of work completed (ProgressCallback), and add a parameter of this type to the DoMath function. In the DoMath code, you should periodically call the passed function: + +``` +typedef void (*ProgressCallback)(const float percent); +  +void DoMath(double &bigdata[], ProgressCallback callback) +{ +   const int N = 1000000; +   for(int i = 0; i < N; ++i) +   { +      if(i % 10000 == 0 && callback != NULL) +      { +         callback(i * 100.0f / N); +      } +       +      // long calculations +   } +} + +``` + +Then the calling code can define the required callback function, pass a pointer to it to DoMath and receive updates as the calculation progresses. + +``` +void MyCallback(const float percent) +{ +   Print(percent); +} +   +void OnStart() +{ +   double data[] = {0}; +   DoMath(data, MyCallback); +} + +``` + +Function pointers work only with custom functions defined in MQL5. They cannot point to [built-in functions](/en/book/common) of the MQL5 API. diff --git a/skills/mql5/references/book/01-basis/0082-basis-functions-functions-inline.md b/skills/mql5/references/book/01-basis/0082-basis-functions-functions-inline.md new file mode 100644 index 0000000..ad46809 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0082-basis-functions-functions-inline.md @@ -0,0 +1,5 @@ +# Inlining + +In order to improve code efficiency, modern compilers often use the following trick. When generating executable code, some function calls are replaced directly by the function body (its statements). This technique is called inlining. This speeds up the operation by avoiding the overhead associated with the organization of the call and return from the function. From a programmer's point of view, inlining doesn't change anything. + +MQL5 supports inlining by default. If necessary, it can be disabled, but only in [code profiling](/en/book/automation/tester/tester_debug_profile) mode. The inline keyword is reserved in MQL5 for compatibility with C++ source codes. Its presence or absence before the function definition does not affect the generated program. diff --git a/skills/mql5/references/book/01-basis/0083-basis-preprocessor.md b/skills/mql5/references/book/01-basis/0083-basis-preprocessor.md new file mode 100644 index 0000000..aea6726 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0083-basis-preprocessor.md @@ -0,0 +1,17 @@ +# Preprocessor + +Up to this moment, we have been studying MQL5 programming, assuming that source codes are processed by the compiler, which converts their textual representation into binary (executable by the terminal). However, the first tool that reads and, if necessary, converts source codes is the preprocessor. This utility built into MetaEditor is controlled by special directives inserted directly into the source code. It can solve a number of problems that programmers face when preparing source codes. + +Similarly to the C++ preprocessor, MQL5 supports the definition of macro substitutions (#define), conditional compilation (#ifdef) and inclusion of other source files (#include ). In this chapter, we will explore these possibilities. Some of them have limitations compared to C++. + +In addition to the standard directives, the MQL5 preprocessor has its own specific ones, in particular, a set of MQL program properties ([#property](/en/book/basis/preprocessor/preprocessor_properties)), and functions import from separate EX5 and DLLs (#import). We will address them in the fifth, sixth and seventh parts when studying various types of MQL programs. + +All preprocessor directives begin with a hash sign '#' followed by a keyword and additional parameters, the syntax of which depends on the type of directive. + +It is recommended to start a preprocessor directive from the very beginning of the line, or at least after a whitespace indent (if the directives are nested). Inserting a directive inside source code statements is considered a bad programming style (unlike MQL5, the C++ preprocessor does not allow this at all). + +Preprocessor directives are not language statements and should not be terminated with a ';'. Directives usually continue to the end of the current line. In some cases, they can be extended in a special way for the following lines, which will be discussed separately. + +The directives are executed sequentially, in the same order in which they occur in the text and taking into account the processing of previous directives. For example, if another file is connected to a file using the [#include](/en/book/basis/preprocessor/preprocessor_include) directive and a substitution rule is defined in the included file using [#define](/en/book/basis/preprocessor/preprocessor_define_simple), then this rule starts working for all subsequent lines of code, including the header files included later. + +The preprocessor does not process comments. diff --git a/skills/mql5/references/book/01-basis/0084-basis-preprocessor-preprocessor-include.md b/skills/mql5/references/book/01-basis/0084-basis-preprocessor-preprocessor-include.md new file mode 100644 index 0000000..656fa64 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0084-basis-preprocessor-preprocessor-include.md @@ -0,0 +1,60 @@ +# Including source files (#include) + +The #include directive is used to include the contents of another file into the source code. The directive produces the same action as if the programmer copies the text from the include file to the clipboard and pastes it into the current file at the place where the directive is used. + +Splitting source code into multiple files is a common practice when writing complex programs. Such programs are built on a modular basis so that each module/file contains logically related code that solves one or more related tasks. + +Include files are also used to distribute libraries (sets of ready-made algorithms). The same library can be included in different programs. In this case, the library update (the update of its header file) will be automatically applied in all programs during their next compilation. + +If the main files of MQL programs must have the mq5 extension, then the include files commonly have the extension mqh ('h' at the end of the word means "header"). At the same time, it is permissible to use the #include directive for other types of text files, for example, *.txt (see below). In any case, when a file is included, the final program combined from the main mq5 file and all headers must still be syntactically correct. For example, including a file with binary information (like a png image) will break the compilation. + +There are two types of #include statements: + +``` +#include  +#include "file_name" + +``` + +In the first one, the file name is enclosed in angle brackets. The compiler searches for such files in the terminal data directory in the MQL5/Include/ subfolder. + +For the second one, with the name in quotes, the search is performed in the same directory which contains the current file that uses the #include statement. + +In both cases, the file can be located in subfolders within the search directory. In this case, you should specify the entire relative hierarchy of folders before the file name in the directive. For example, along with MetaTrader 5, there are many commonly used boot files, among which is DateTime.mqh with a set of methods for working with date and time (they are designed as structures, the language constructs that we will discuss in Part 3 devoted to OOP). The DateTime.mqh file is located in the Tools folder. To include it in your source code, you should use the following directive: + +``` +#include  + +``` + +To demonstrate how to include a header file from the same folder as the source file with the directive, let's consider the file Preprocessor.mq5. It contains the following directive: + +``` +#include "Preprocessor.mqh" + +``` + +It refers to the Preprocessor.mqh file, which is really located next to Preprocessor.mq5. + +An include file can, in turn, include other files. In particular, inside Preprocessor.mqh there is the following code: + +``` +double array[] = +{ +   #include "Preprocessor.txt" +}; + +``` + +It means that the contents of the array are initialized from the given text file. If we look inside Preprocessor.txt, we will see the text that complies with the array initialization syntax rules: + +``` +1, 2, 3, 4, 5 + +``` + +Thus, it is possible to collect source code from custom components, including generating it using other programs. + +Note that if the file specified in the directive is not found, the compilation will fail. + +The order in which multiple files are included determines the order in which the preprocessor directives in them are processed. diff --git a/skills/mql5/references/book/01-basis/0085-basis-preprocessor-preprocessor-define-overview.md b/skills/mql5/references/book/01-basis/0085-basis-preprocessor-preprocessor-define-overview.md new file mode 100644 index 0000000..30b54c3 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0085-basis-preprocessor-preprocessor-define-overview.md @@ -0,0 +1,18 @@ +# Overview of macro substitution directives + +Macro substitution directives include two forms of the #define directive: + +- simple, usually to define a constant +- defining a macro as a pseudo-function with parameters + +In addition, there is a #undef directive to undo any of the previous #define definitions. If #undef is not used, each defined macro is valid until the end of source compilation. + +Macros are registered and then used in code by name, following the rules of identifiers. By convention, macro names are written in capital letters. Macro names can overlap the names of variables, functions, and other elements of the source code. Purposeful use of this fact allows the flexibility to change and generate source code on the fly. However, an unintentional coincidence of a macro name with a program element will result in errors. + +The principle of operation of both forms of macro substitutions is the same. Using the #define directive, an identifier is introduced, which is associated with a certain piece of text — a definition. If the preprocessor finds a given identifier later in the source code, it replaces it with the text associated with it. We emphasize that the macro name can be used in compiled code only after registration (this is similar to the variable declaration principles, but only at the compilation stage). + +Replacing a macro name with its definition is called expansion. The analysis of the source code occurs progressively and by one line in a pass, but the expansion in each line can be performed an arbitrary number of times, as in a loop, as long as macro names are found in the result. You cannot include the same name in a macro definition: when substituting, such a macro will result in an "unknown identifier" error. + +In Part 3 of the book, we'll learn about [templates](/en/book/oop/templates), which also allow you to generate (or, in fact, replicate) source code, but with different rules. If there are both, macro substitution directives and templates in the source code, the macros are expanded first, and then the code is generated from the templates. + +Macro names are highlighted in red in MetaEditor. diff --git a/skills/mql5/references/book/01-basis/0086-basis-preprocessor-preprocessor-define-simple.md b/skills/mql5/references/book/01-basis/0086-basis-preprocessor-preprocessor-define-simple.md new file mode 100644 index 0000000..190fca3 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0086-basis-preprocessor-preprocessor-define-simple.md @@ -0,0 +1,141 @@ +# Simple form of #define + +The simple form of the #define directive registers an identifier and the character sequence by which the identifier should be replaced everywhere in the source codes after the directive, up to the end of the program, or before the #undef directive with the same identifier. + +Its syntax is: + +``` +#define macro_identifier [text] + +``` + +The text starts after the identifier and continues to the end of the current line. The identifier and text must be separated by an arbitrary number of spaces or tabs. If the required sequence of characters is too long, then for readability you can split it into several lines by putting a backslash character '\' at the end of the line. + +``` +#define macro_identifier text_beginning \ +                           text_continued \ +                           text_ending + +``` + +The text can consist of any language constructs: constants, operators, identifiers, and punctuation marks. If you substitute macro_identifier instead of the found constructs in the source code, all of them will be included in the compilation. + +The simple form is traditionally used for several purposes: + +1. Flag declarations, which are then used for [conditional compilation](/en/book/basis/preprocessor/preprocessor_ifdefs) checks; +2. Named constant declarations; +3. Abbreviated notation of common statements. + +The first point is characterized by the fact that nothing needs to be specified after the identifier - the presence of a directive with a name is already enough for the corresponding identifier to be registered and can be used in conditional directives [#ifdef/ifndef](/en/book/basis/preprocessor/preprocessor_ifdefs). For them, it is only important whether the identifier exists or not, i.e. it works in the flag mode: declared / not declared. For example, the following directive defines the DEMO flag: + +``` +#define DEMO + +``` + +It can then be used, say, to build a demo version of the program from which certain functions are excluded (see the example in the conditional compilation section). + +The second way to use a simple directive allows you to replace the "magic numbers" in the source code with friendly names. "Magic numbers" are constants inserted into the source text, the meaning of which is not always clear (because a number is just a number: it is desirable to at least explain it in a comment). In addition, the same value can be scattered throughout different parts of the code, and if the programmer decides to change it to another, then he will have to do this in all places (and hope that he did not miss anything). + +With a named macro, these two problems are easily solved. For example, a script can prepare an array with Fibonacci numbers to a certain maximum depth. Then it makes sense to define a macro with a predefined array size and use it in the description of the array itself (Preprocessor.mq5). + +``` +#define MAX_FIBO 10 +  +int fibo[MAX_FIBO]; // 10 +  +void FillFibo() +{ +   int prev = 0; +   int result = 1; +  +   for(int i = 0; i < MAX_FIBO; ++i) // i < 10 +   { +      int temp = result; +      result = result + prev; +      fibo[i] = result; +      prev = temp; +   } +} + +``` + +If the programmer subsequently decides that the size of the array needs to be increased, it is enough for him to do this in one place - in the #define directive. Thus, the directive actually defines a certain parameter of the algorithm, which is "hardwired" into the source code and is not available for user configuration. The need for this arises quite often. + +The question may arise how defining through #define differs from a constant variable in the global context. Indeed, we could declare a variable with the same name and purpose, and even preserve the uppercase letters: + +``` +const int MAX_FIBO = 10; + +``` + +However, in this case, MQL5 will not allow defining an array with the specified size, since only constants are allowed in square brackets, i.e. literals (and a constant variable, despite its similar name, is not a constant). To solve this problem, we could define an array as dynamic (without specifying a size first) and then allocate memory for it using the [ArrayResize](/en/book/common/arrays/arrays_dynamic) function - passing a variable as a size is not difficult here. + +An alternative way to define a named constant is provided by enums, but is limited to integer values ​​only. For example: + +``` +enum +{ +   MAX_FIBO = 10 +}; + +``` + +But macro can contain a value of any type. + +``` +#define TIME_LIMIT     D'2023.01.01'  +#define MIN_GRID_STEP  0.005 + +``` + +The search for macro names in source texts for replacement is performed taking into account the syntax of the language, that is, indivisible elements, such as variable identifiers or string literals, will remain unchanged, even if they include a substring that matches one of the macros. For example, given the macro XYZ below, the variable XYZAXES will be kept as it is, and the name XYZ (because it is exactly the same as the macro) will be changed to ABC. + +``` +#define XYZ ABC +int XYZAXES = 3; // int XYZAXES = 3 +int XYZ = 0;     // int ABC = 0 + +``` + +Macro substitutions allow you to embed your code in the source code of other programs. This technique is usually used by libraries that are distributed as mqh header files and connected to programs using the [#include](/en/book/basis/preprocessor/preprocessor_include) directives. + +In particular, for scripts, we can define our own library implementation of the OnStartfunction, which must perform some additional actions without affecting the original functionality of the program. + +``` +void OnStart() +{ +   Print("OnStart wrapper started"); +   // ... additional actions +   _OnStart(); +   // ... additional actions +   Print("OnStart wrapper stopped"); +} +  +#define OnStart _OnStart + +``` + +Suppose this part is in the included header file (Preprocessor.mqh). + +Then the original function OnStart (in Preprocessor.mq5) will be renamed by the preprocessor in the source code to _OnStart (it is understood that this identifier is not used anywhere else for some other purpose). And the new version of OnStart from the header calls _OnStart, "wrapping" it into additional statements. + +The third common way to use the simple #define is to shorten the notation of language constructs. For example, the title of an infinite loop can be denoted with one word LOOP: + +``` +#define LOOP for( ; !IsStopped() ; ) + +``` + +And then applied in code: + +``` +LOOP +{ +   // ... +   Sleep(1000); +} + +``` + +This method is also the main technique for using the #define directive with parameters (see below). diff --git a/skills/mql5/references/book/01-basis/0087-basis-preprocessor-preprocessor-define-functional.md b/skills/mql5/references/book/01-basis/0087-basis-preprocessor-preprocessor-define-functional.md new file mode 100644 index 0000000..5a78650 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0087-basis-preprocessor-preprocessor-define-functional.md @@ -0,0 +1,122 @@ +# #define form as a pseudo-function + +The syntax of the parametric form #define is similar to a function. + +``` +#define macro_identifier(parameter,...) text_with_parameters + +``` + +Such a macro has one or more parameters in parentheses. Parameters are separated by commas. Each parameter is a simple identifier (often a single letter). Moreover, all parameters of one macro must have different identifiers. + +It is important that there is no space between the identifier and the opening parenthesis, otherwise the macro will be treated as a simple form in which the replacement text starts with an opening parenthesis. + +After this directive is registered, the preprocessor will search the source codes for lines of the form: + +``` +macro_identifier(expression,...) + +``` + +Arbitrary expressions can be specified instead of parameters. The number of arguments must match the number of macro parameters. All found occurrences will be replaced with text_with_parameters, in which, in turn, the parameters will be replaced with the passed expressions. Each parameter can occur several times, in any order. + +For example, the following macro finds the maximum of two values: + +``` +#define MAX(A,B) ((A) > (B) ? (A) : (B)) + +``` + +If the code contains the statement: + +``` +int z = MAX(x, y); + +``` + +it will be "expanded" by the preprocessor into: + +``` +int z = ((x) > (y) ? (x) : (y)); + +``` + +Macro substitution will work for any data type (for which the operations applied inside the macro are valid). + +However, substitution can also have side effects. For example, if the actual parameter is a function call or statement that modifies the variable (say, ++x), then the corresponding action can be performed multiple times (instead of the intended one time). In the case of MAX, this will happen twice: during the comparison and when getting values in one of the branches of the '?:' operator. In this regard, it makes sense to convert such macros into functions whenever possible (especially considering that in MQL5 functions are automatically inlined). + +There are parentheses around the parameters and around the entire macro definition. They are used to ensure that the substitution of expressions as parameters or the macro itself inside other expressions does not distort the computing order due to different priorities. Let's say the macro defines the multiplication of two parameters (not yet enclosed in parentheses): + +``` +#define MUL(A,B) A * B + +``` + +Then the use of the macro with the following expressions will produce unexpected results: + +``` +int x = MUL(1 + 2, 3 + 4); // 1 + 2 * 3 + 4 + +``` + +Instead of multiplication (1 + 2) * (3 + 4) which gives 21, we have 1 + 2 * 3 + 4, i.e., 11. The appropriate macro definition should be like this: + +``` +#define MUL(A,B) ((A) * (B)) + +``` + +You can specify another macro as a macro parameter. In addition, you can also insert other macros in a macro definition. All such macros will be replaced sequentially. For example: + +``` +#define SQ3(X) (X * X * X) +#define ABS(X) MathAbs(SQ3(X)) +#define INC(Y) (++(Y)) + +``` + +Then the following code will print 504 (MathAbs is a built-in function that returns the modulus of a number, i.e. without a sign): + +``` +int x = -10; +Print(ABS(INC(x))); +// -> ABS(++(Y)) +// -> MathAbs(SQ3(++(Y))) +// -> MathAbs((++(Y))*(++(Y))*(++(Y))) +// -> MathAbs(-9*-8*-7) +// -> 504 + +``` + +In the variable x, the value -7 will remain (due to the triple increment). + +A macro definition can contain unmatched parentheses. This technique is used, as a rule, in a pair of macros, one of which should open a certain piece of code, and the other should close it. In this case, unmatched parentheses in each of them will become matched. In particular, in standard library files available in the MetaTrader 5 distribution package, in Controls/Defines.mqh, the EVENT_MAP_BEGIN and EVENT_MAP_END macros are defined. They are used to form the event processing function in graphical objects. + +The preprocessor reads the entire source text of the program line by line, starting from the main mq5 file and inserting the texts from the header files encountered in place. By the time any line of code is read, a certain set of macros that are already defined is formed. It does not matter in which order the macros were defined: it is quite possible that one macro refers in its definition to another, which was described both above and below in the text. It is only important that in the line of source code where the macro name is used, the definitions of all referenced macros are known. + +Consider an example. + +``` +#define NEG(x) (-SQN(x))*TEN +#define SQN(x) ((x)*(x)) +#define TEN 10 +... +Print(NEG(2)); // -40 + +``` + +Here, the NEG macro uses the SQN and TEN macros, which are described below it. And this does not prevent us from successfully using it in the code after all three #define-s. + +However, if we change the relative position of the rows to the following: + +``` +#define NEG(x) (-SQN(x))*TEN +#define SQN(x) ((x)*(x)) +... +Print(NEG(2)); // error: 'TEN' - undeclared identifier +... +#define TEN 10 + +``` + +we get an "undeclared identifier" compilation error. diff --git a/skills/mql5/references/book/01-basis/0088-basis-preprocessor-preprocessor-sharp.md b/skills/mql5/references/book/01-basis/0088-basis-preprocessor-preprocessor-sharp.md new file mode 100644 index 0000000..23a4a30 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0088-basis-preprocessor-preprocessor-sharp.md @@ -0,0 +1,68 @@ +# Special operators '#' and '##' inside #define definitions + +Inside macro definitions, two special operators can be used: + +- a single hash symbol '#' before the name of a macro parameter turns the contents of that parameter into a string; it is allowed only in function macros; +- a double hash symbol '##' between two words (tokens) combines them, and if the token is a macro parameter, then its value is substituted, but if the token is a macro name, it is substituted as is, without expanding the macro; if as a result of "gluing" another macro name is obtained, it is expanded; + +In the examples in this book, we often used the following macro: + +``` +#define PRT(A) Print(#A, "=", (A)) + +``` + +It calls the Print function, in which the passed expression is displayed as a string thanks to #A, and after the sign "equal", the actual value of A is printed. + +To demonstrate '##', let's consider another macro: + +``` +#define COMBINE(A,B,X) A##B(X) + +``` + +With it, we can actually generate a call to the SQN macro defined above: + +``` +Print(COMBINE(SQ,N,2)); // 4 + +``` + +The literals SQ and N are concatenated, after which the macro SQN expands to ((2)*(2)) and produces the result 4. + +The following macro allows you to create a variable definition in code by generating its name given the parameters of the macro: + +``` +#define VAR(TYPE,N) TYPE var##N = N + +``` + +Then the line of code: + +``` +VAR(int, 3); + +``` + +is equivalent to the following: + +``` +int var3 = 3; + +``` + +Concatenation of tokens allows the implementation of a loop shorthand over the array elements using a macro. + +``` +#define for_each(I, A) for(int I = 0, max_##I = ArraySize(A); I < max_##I; ++I) +   +// describe and somehow fill in the array x +double x[]; +// ... +// implement loop through the array +for_each(i, x) +{ +   x[i] = i * i; +} + +``` diff --git a/skills/mql5/references/book/01-basis/0089-basis-preprocessor-preprocessor-undef.md b/skills/mql5/references/book/01-basis/0089-basis-preprocessor-preprocessor-undef.md new file mode 100644 index 0000000..3722cc9 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0089-basis-preprocessor-preprocessor-undef.md @@ -0,0 +1,12 @@ +# Cancelling macro substitution (#undef) + +Substitutions registered with #define can be undone if they are no longer needed after a particular piece of code. For these purposes, the #undef directive is used. + +``` +#undef macro_identifier + +``` + +In particular, it is useful if you need to define the same macro in different ways in different parts of the code. If the identifier specified in #define has already been registered somewhere in earlier lines of code (by another #define directive), then the old definition is replaced with the new one, and the preprocessor generates the "macro redefinition" warning. The use of #undef avoids the warning while explicitly indicating the programmer's intention not to use a particular macro further down the code. + +#undef cannot undefine [predefined macros](/en/book/basis/preprocessor/preprocessor_predefined). diff --git a/skills/mql5/references/book/01-basis/0090-basis-preprocessor-preprocessor-predefined.md b/skills/mql5/references/book/01-basis/0090-basis-preprocessor-preprocessor-predefined.md new file mode 100644 index 0000000..b49d7d7 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0090-basis-preprocessor-preprocessor-predefined.md @@ -0,0 +1,18 @@ +# Predefined preprocessor constants + +MQL5 has several predefined constants that are equivalent to simple macros, but they are defined by the compiler itself. The following table lists some of their names and meanings. + +| Name | Description | +| --- | --- | +| __COUNTER__ | Counter (each mention in the text during macro expansion results in an increase of 1) | +| __DATE__ | Compilation date (day) | +| __DATETIME__ | Compilation date and time | +| __FILE__ | The name of the compiled file | +| __FUNCSIG__ | Current function signature | +| __FUNCTION__ | Current function name | +| __LINE__ | Line number in the compiled file | +| __MQLBUILD__, __MQL5BUILD__ | Compiler version | +| __RANDOM__ | Random number of type ulong | +| __PATH__ | Path to compiled file | +| _DEBUG | Defined when compiling in debug mode | +| _RELEASE | Defined when compiling in normal mode | diff --git a/skills/mql5/references/book/01-basis/0091-basis-preprocessor-preprocessor-ifdefs.md b/skills/mql5/references/book/01-basis/0091-basis-preprocessor-preprocessor-ifdefs.md new file mode 100644 index 0000000..327269b --- /dev/null +++ b/skills/mql5/references/book/01-basis/0091-basis-preprocessor-preprocessor-ifdefs.md @@ -0,0 +1,53 @@ +# Conditional compilation (#ifdef/#ifndef/#else/#endif) + +Conditional compilation directives allow you to include and exclude code fragments from the compilation process. The #ifdef and #ifndef directives mark the beginning of the code fragment they control. The fragment ends with the #endif directive. In the simplest case, the #ifdef syntax is as follows: + +``` +#ifdef macro_identifier +  statements +#endif + +``` + +If a macro with the specified identifier is defined above in the code using #define, then this code fragment will participate in compilation. Otherwise, it is excluded. In addition to the macros defined in the application code, the environment provides a set of predefined constants, in particular, the _RELEASE and _DEBUG flags (see section [Predefined constants](/en/book/basis/preprocessor/preprocessor_predefined)): their names can also be checked in conditional compilation directives. + +The extended form #ifdef allows the specification of two pieces of code: the first will be included if the macro identifier is defined, and the second if it is not. To do this, a fragment separator #else is inserted between #ifdef and #endif. + +``` +#ifdef macro_identifier +  statesments_true +#else +  statements_false +#endif + +``` + +The #ifndef directive works similarly, but fragments are included and excluded according to the reverse logic: if the macro specified in the header is not defined, the first fragment is compiled, and if it is defined, the second fragment is compiled. + +For example, depending on the presence of the DEMO macro substitution, we may or may not call the function for calculating Fibonacci numbers. + +``` +#ifdef DEMO +   Print("Fibo is disabled in the demo"); +#else +   FillFibo(); +#endif + +``` + +In this case, if the DEMO mode is enabled, instead of calling the function, a message would be displayed in the log, but since in the Preprocessor.mq5 script and all the included files there is no #define DEMO definition, compilation proceeds according to branch #else, that is, the call to the FillFibo function gets into the executable ex5 file. + +Directives can be nested. + +``` +#ifdef _DEBUG +   Print("Debugging"); +#else +   #ifdef _RELEASE +      Print("Normal run"); +   #else +      Print("Undefined mode!"); +   #endif +#endif + +``` diff --git a/skills/mql5/references/book/01-basis/0092-basis-preprocessor-preprocessor-properties.md b/skills/mql5/references/book/01-basis/0092-basis-preprocessor-preprocessor-properties.md new file mode 100644 index 0000000..76193c6 --- /dev/null +++ b/skills/mql5/references/book/01-basis/0092-basis-preprocessor-preprocessor-properties.md @@ -0,0 +1,31 @@ +# General program properties (#property) + +Using the #property directive, a programmer can set some properties of an MQL program. Some of these properties are general, that is, applicable to any program, and we will consider them here. The remaining properties are typical for specific types of MQL5 programs and will be discussed in the relevant sections of Part 5 when describing the MQL5 API. + +Directive #property has the following format: + +``` +#property key value + +``` + +The key is one of the properties listed in the following table, in the first column. The second column specifies how the value will be interpreted. + +| Property | Value | +| --- | --- | +| copyright | String with information about the copyright holder | +| link | String with a link to the developer's site | +| version | String with the program version number (for the MQL5 Market, it must be in the "X.Y" format, where X and Y are integers corresponding to the major and minor build numbers) | +| description | Line with program description (several #description directives are allowed and their contents are combined) | +| icon | String, path to the file with the program logo in ICO format | +| stacksize | Integer specifying the size of the stack in bytes (by default it is from 4 to 16 MB, depending on the type of program and environment, 1 MB = 1024*1024 bytes); if necessary, the size increases up to 64 MB (maximum) | + +All aforementioned string properties are the source of information for the program's properties dialog, which opens when it starts. However, for scripts, this dialog is not displayed by default. To change this behavior, you must additionally specify the #property [script_show_inputs](/en/book/applications/script_service/scripts) directive. In addition, information about the rights is displayed in a tooltip when hovering the mouse cursor over the program in the MetaTrader 5 Navigator. + +The copyright, link, and version properties have already been seen in all the previous examples in this book. + +The stack size stacksize is a recommendation: if the compiler finds local variables (usually arrays) in the source code that exceed the specified value, the stack will be automatically increased during compilation, but up to no more than 64 MB. If the limit is exceeded, the program will not even be able to start: in the log (tab Log, and not Experts) the error "Stack size of 64MB exceeded. Reduce the memory occupied by local variables" will occur. + +Please note that such analysis and launch prevention only take into account a fixed snapshot of the program at the time of launch. In the case of recursive function calls, the stack memory consumption can increase significantly and lead to a stack overflow error, but already at the program execution stage. For more information about the stack, see the note in [Describing arrays](/en/book/basis/arrays/arrays_declaration). + +The #property directives work only in the compiled mq5 file, and are ignored in all those included with #include. diff --git a/skills/mql5/references/book/01-basis/pics/debug23_en.png b/skills/mql5/references/book/01-basis/pics/debug23_en.png new file mode 100644 index 0000000..06b96dd Binary files /dev/null and b/skills/mql5/references/book/01-basis/pics/debug23_en.png differ diff --git a/skills/mql5/references/book/01-basis/pics/debug24_en.png b/skills/mql5/references/book/01-basis/pics/debug24_en.png new file mode 100644 index 0000000..ab355fe Binary files /dev/null and b/skills/mql5/references/book/01-basis/pics/debug24_en.png differ diff --git a/skills/mql5/references/book/01-basis/pics/inputs-en.png b/skills/mql5/references/book/01-basis/pics/inputs-en.png new file mode 100644 index 0000000..88c9707 Binary files /dev/null and b/skills/mql5/references/book/01-basis/pics/inputs-en.png differ diff --git a/skills/mql5/references/book/01-basis/pics/me_breakpoint_en.png b/skills/mql5/references/book/01-basis/pics/me_breakpoint_en.png new file mode 100644 index 0000000..235c6d1 Binary files /dev/null and b/skills/mql5/references/book/01-basis/pics/me_breakpoint_en.png differ diff --git a/skills/mql5/references/book/02-oop/0093-oop.md b/skills/mql5/references/book/02-oop/0093-oop.md new file mode 100644 index 0000000..39ea8b4 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0093-oop.md @@ -0,0 +1,22 @@ +# Object Oriented Programming in MQL5 + +At some point during the process of software development, the problem of the built-in types and set of functions not being sufficient for the effective implementation of requirements becomes apparent. The complexity of managing many small entities that make up the program grows like a snowball and requires using some kind of technology capable of improving the convenience, productivity, and quality of the programmer's work. + +One of these technologies, implemented at the level of many programming languages, is called Object-Oriented, and the programming style based on it is called Object-Oriented Programming (OOP), respectively. The MQL5 programming language also supports it and therefore belongs to the family of object-oriented languages, like C++. + +From the name of the technology, it can be concluded that it is organized around objects. Essentially, an object is a variable of a user-defined type, i.e., a type defined by a programmer using MQL5 tools. The opportunity to create types that model the subject area makes programs more understandable and simplifies their writing and maintenance. + +In MQL5, there are several methods to define a new type, and each method is characterized by some features that we will describe in the relevant sections. Depending on the method of description, user-defined types are divided into classes, structures, and associations. Each of them can combine data and algorithms, i.e., describe the state and behavior of applied objects. + +In Part 1 of the book, we brought up the quote from one of the fathers of programming, Nicklaus Wirth, that programs are a symbiosis of algorithms and data structures. So, the objects are essentially mini-programs — each is responsible for solving its own, albeit small, but logically complete task. By composing objects into a single system, you can build a service or product of arbitrary complexity. Thus, with the OOP we get a new interpretation of the principle of "divide and conquer". + +OOP should be thought of as a more powerful and flexible alternative to the procedural programming style we explored in Part Two. At the same time, both approaches should not be contrasted: if necessary, they can be combined, and in the simplest tasks, OOP can be left aside. + +So, in this third Part of the book, we will study the basics of OOP and the possibilities of their practical implementation in MQL5. In addition, we will talk about templates, interfaces, and namespaces. + +``` +MQL5 Programming for Traders — Source Codes from the Book. Part 3 + +Examples from the book are also available in the public project \MQL5\Shared Projects\MQL5Book + +``` diff --git a/skills/mql5/references/book/02-oop/0094-oop-structs-and-unions.md b/skills/mql5/references/book/02-oop/0094-oop-structs-and-unions.md new file mode 100644 index 0000000..91d368c --- /dev/null +++ b/skills/mql5/references/book/02-oop/0094-oop-structs-and-unions.md @@ -0,0 +1,7 @@ +# Structures and unions + +A structure is the object type that is easiest to understand, so we'll start our introduction to OOP with it. Structures have a lot in common with classes, which are the main building blocks in OOP, so knowledge of structures will help in the future when moving to classes. At the same time, structures have certain differences, some of which can be considered limitations, and some are considered advantages. In particular, structures cannot have [virtual functions](/en/book/oop/classes_and_interfaces/classes_virtual_override), but they can be used for integration with third-party DLLs. + +The choice between structures and classes in the implementation of the algorithm is traditionally based on the requirements for access to the elements of the object and the presence of internal business logic. If a simple container with structured data is needed and its state does not need to be checked for correctness (in programming this is called an "invariant"), then a structure will do just fine. If you want to restrict access and support writing and reading according to some rules (which are formalized in the form of functions assigned to the object, which we will discuss later), then it is better to use classes. + +MQL5 has built-in types of structures that describe entities that are in demand for trading, in particular, rates (MqlRates), ticks (MqlTick), date and time (MqlDateTime), trade requests (MqlTradeRequest), requests' results (MqlTradeResult) and many others. We will talk about them in Part 6 of this book. diff --git a/skills/mql5/references/book/02-oop/0095-oop-structs-and-unions-structs-definition.md b/skills/mql5/references/book/02-oop/0095-oop-structs-and-unions-structs-definition.md new file mode 100644 index 0000000..efe67f0 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0095-oop-structs-and-unions-structs-definition.md @@ -0,0 +1,116 @@ +# Definition of structures + +A structure consists of variables, which can be built-in or other user-defined types. The purpose of the structure is to combine logically related data in a single container. Suppose we have a function that performs a certain calculation and accepts a set of parameters: number of bars that show a history of quotes for analysis, date when the analysis started, price type, and number of signals allocated (for example, harmonics). + +``` +double calculate(datetime start, int barNumber, +                 ENUM_APPLIED_PRICE price, int components); + +``` + +In reality, there may be more parameters and it won't be easy to pass them to the function as a list. Moreover, based on the results of several calculations, it makes sense to save some of the best settings in some kind of array. Therefore, it is convenient to represent a set of parameters as a single object. + +The description of the structure with the same variables looks as follows: + +``` +struct Settings +{ +   datetime start; +   int barNumber; +   ENUM_APPLIED_PRICE price; +   int components; +}; + +``` + +The description starts with the keyword struct followed by the identifier of our choice. This is followed by a block of code in curly brackets, and inside it are descriptions of variables included in the structure. Additionally, these are called fields or members of a structure. There is a semicolon after the curly brackets since the whole notation is a statement defining a new type, and ';' is required after statements. + +Once the type is defined, we can apply it in the same way as built-in types. In particular, the new type allows you to describe variable Settings in the program in the usual way. + +``` +Settings s; + +``` + +It is important to note that a single structure description allows you to create an arbitrary number of structure variables and even arrays of this type. Each structure instance will have its own set of elements, and they will contain independent values. + +To access members of a structure, a special dereference operator is provided – the dot character '.'. To the left of it should be a variable of structure type, and to the right – an identifier of one of the fields available in it. Here's how you can assign a value to a structure element: + +``` +void OnStart() +{ +   Settings s; +   s.start = D'2021.01.01'; +   s.barNumber = 1000; +   s.price = PRICE_CLOSE; +   s.components = 8; +} + +``` + +There is a more convenient way to fill in the structure which is the aggregate initialization. In this case, the sign '=' is written to the right of the structure variable, followed by a comma-separated list of initial values ​​of all fields in curly brackets. + +``` +   Settings s = {D'2021.01.01', 1000, PRICE_CLOSE, 8}; + +``` + +The types of the value must match the corresponding element types. It is allowed to specify fewer values than the number of fields: then the remaining fields will receive zero values. + +Note that this method only works when the variable is initialized, at the time of its definition. It is impossible to assign the contents of an already existing structure in this way, we will get a compilation error. + +``` +   Settings s; +   // error: '{' - parameter conversion not allowed +   s = {D'2021.01.01', 1000, PRICE_CLOSE, 8}; + +``` + +Using the dereference operator, you can also read the value of a structure element. For example, we use the number of bars to calculate the number of components. + +``` +   s.components = (int)(MathSqrt(s.barNumber) + 1); + +``` + +Here MathSqrt is the built-in [square root](/en/book/common/maths/maths_pow_sqrt) function. + +We have introduced a new type, Settings, to make it easier to pass a set of parameters to a function. Now it can be used as the only parameter of the updated function calculate: + +``` +double calculate(Settings &settings); + +``` + +Notice the ampersand '&' in front of the parameter name, which means [passing by reference](/en/book/basis/functions/functions_ref_value). Structures can only be passed as parameters by reference. + +Structures are also useful if you need to return a set of values from a function rather than a single value. Let's imagine that the calculate function should return not a value of the type double, but several coefficients and some trading recommendations (trade direction and probability of success). Then we can define the type of the structure Result and use it in the function prototype (Structs.mq5). + +``` +struct Result +{ +   double probability; +   double coef[3]; +   int direction; +   string status; +}; +  +Result calculate(Settings &settings) +{ +   if(settings.barNumber > 1000) // edit fields +   { +      settings.components = (int)(MathSqrt(settings.barNumber) + 1); +   } +   // ... +   // emulate getting the result +   Result r = {}; +   r.direction = +1; +   for(int i = 0; i < 3; i++) r.coef[i] = i + 1; +   return r; +} + +``` + +The empty curly brackets in the line Result r = {} represent the minimal aggregate initializer: it fills all fields of the structure with zeros. + +The definition and declaration of the structure type can, if necessary, be done separately (as a rule, the declaration goes in the header mqh file, and the definition is in the mq5 file). This extended syntax will be covered in the [Chapter on Classes](/en/book/oop/classes_and_interfaces/classes_declaration_definition). diff --git a/skills/mql5/references/book/02-oop/0096-oop-structs-and-unions-structs-methods.md b/skills/mql5/references/book/02-oop/0096-oop-structs-and-unions-structs-methods.md new file mode 100644 index 0000000..cc1230f --- /dev/null +++ b/skills/mql5/references/book/02-oop/0096-oop-structs-and-unions-structs-methods.md @@ -0,0 +1,49 @@ +# Functions (methods) in structures + +After receiving a result from the calculate function, it would be desirable to print it to the log, but the Print function does not work with user-defined types: they themselves must provide a way to output information. + +``` +void OnStart() +{ +   Settings s = {D'2021.01.01', 1000, PRICE_CLOSE, 8}; +   Result r = calculate(s); +   // Print(r);  // error: 'r' - objects are passed by reference only +   // Print(&r); // error: 'r' - class type expected +} + +``` + +The comments show the attempts to call the Print function for the structure, and what follows thereafter. The first error is caused by the fact that structure instances are objects, and objects must be passed to functions by reference. At the same time, Print is expecting a value (one or several). The use of an ampersand before the variable name in the second Print call means in MQL5 that the pointer is received, and it is not a reference as one might think. Pointers in MQL5 are only supported for class objects (not structures), hence the second "class type expected" error. We will learn more about pointers in the next chapter (see [Classes and interfaces](/en/book/oop/classes_and_interfaces)). + +We could specify in the Print call all the members of the structure separately (using dereference), but this is rather troublesome. + +For those cases when it is necessary to process the contents of the structure in a special way, it is possible to define functions inside the structure. The syntax of the definition is no different from the familiar global context functions, but the definition itself is located inside the structure block. + +Such functions are called methods. Since they are located in the context of the corresponding block, the fields of the structure can be accessed from them without the dereference operator. As an example, let's write the implementation of the function print in the Resultstructure. + +``` +struct Result +{ +   ... +   void print() +   { +      Print(probability, " ", direction, " ", status); +      ArrayPrint(coef); +   } +}; + +``` + +Calling a method of the structure instance is as simple as reading its field: the same '.' operator is used. + +``` +void OnStart() +{ +   Settings s = {D'2021.01.01', 1000, PRICE_CLOSE, 8}; +   Result r = calculate(s); +   r.print(); +} + +``` + +[Chapter on Classes](/en/book/oop/classes_and_interfaces) will cover methods in more detail. diff --git a/skills/mql5/references/book/02-oop/0097-oop-structs-and-unions-structs-assignment.md b/skills/mql5/references/book/02-oop/0097-oop-structs-and-unions-structs-assignment.md new file mode 100644 index 0000000..31c3c8e --- /dev/null +++ b/skills/mql5/references/book/02-oop/0097-oop-structs-and-unions-structs-assignment.md @@ -0,0 +1,29 @@ +# Copying structures + +Structures of the same type can be copied entirely into each other using the '=' assignment operator. Let's demonstrate this rule using an example of the structure Result. We get the first instance of r from the calculate function. + +``` +void OnStart() +{ +   ... +   Result r = calculate(s); +   r.print(); +   // will output to the log: +   // 0.5 1 ok +   // 1.00000 2.00000 3.00000 +   ... +   Result r2; +   r2 = r; +   r2.print(); +   // will output to the log the same values: +   // 0.5 1 ok +   // 1.00000 2.00000 3.00000 +} + +``` + +Then, the variable Result r2 was additionally created, and the contents of the r variable, all fields concurrently, were duplicated into it. The accuracy of the operation can be verified by outputting to the log using the method print (the lines are given in the comments). + +It should be noted that defining two types of structures with the same set of fields does not make the two types the same. It is not possible to assign a structure to another one completely, only memberwise assignment is permitted in such cases. + +A little later, we'll talk about structure inheritance, which will give you more options for copying. The fact is that copying works not only between structures of the same type but also between related types. However, there are important nuances, which we will cover in the [Layout and inheritance of structures](/en/book/oop/structs_and_unions/structs_composition) section. diff --git a/skills/mql5/references/book/02-oop/0098-oop-structs-and-unions-structs-ctor-dtor.md b/skills/mql5/references/book/02-oop/0098-oop-structs-and-unions-structs-ctor-dtor.md new file mode 100644 index 0000000..4eea6e3 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0098-oop-structs-and-unions-structs-ctor-dtor.md @@ -0,0 +1,122 @@ +# Constructors and destructors + +Among the methods that can be defined for a structure, there are special ones: constructors and destructors. + +A constructor has the same name as the structure name and does not return a value (type void). The constructor, if defined, will be called at the time of initialization for each new instance of the structure. Due to this, in the constructor, the initial state of the structure can be calculated in a special way. + +A structure can have multiple constructors with different sets of parameters, and the compiler will choose the appropriate one based on the number and type of arguments when defining the variable. + +For example, we can describe a pair of constructors in the structure Result: one without parameters, and the second one with one string type parameter to set the status. + +``` +struct Result +{ +   ... +   void Result() +   { +      status = "ok"; +   } +   void Result(string s) +   { +      status = s; +   } +}; + +``` + +By the way, a constructor without parameters is called a default constructor. If there are no explicit constructors, the compiler implicitly creates a default constructor for any structure that contains strings and dynamic arrays to pad these fields with zeros. + +It is important that fields of other types (for example, all numeric) are not reset to zero, regardless of whether the structure has a default constructor, and therefore the initial values of the elements after memory allocation will be random. You should either create constructors or make sure that the correct values are assigned in your code immediately after the object is created. + +The presence of explicit constructors makes it impossible to use the aggregate initialization syntax. Because of it, the line Result r = {}; in the calculate method will not be compiled. Now we have the right to use only one of the constructors that we provided ourselves. For example, the following statements call the parameterless constructor: + +``` +   Result r1; +   Result r2(); + +``` + +And creating a structure with a filled status can be done like this: + +``` +   Result r3("success"); + +``` + +The default constructor (explicit or implicit) is also called when an array of structures is created. For example, the following statement allocates memory for 10 structures with results and initializes them with a default constructor: + +``` +   Result array[10]; + +``` + +A destructor is a function that will be called when the structure object is being destroyed. The destructor has the same name as the structure name, but is prefixed with a tilde character '~'. The destructor, like the constructor, does not return a value, but it does not take parameters either. + +There can only be one destructor. + +You cannot explicitly call the destructor. The program itself does this when exiting a block of code where a local structure variable was defined, or when freeing an array of structures. + +The purpose of the destructor is to release any dynamic resources if the structure allocated them in the constructor. For example, a structure can have the persistence property, that is, save its state to a file when it is unloaded from memory and restore it when the program creates it again. In this case, a descriptor that needs to be opened and closed is used in the built-in [file functions](/en/book/common/files). + +Let's define a destructor in the Result structure and add constructors along the way so that all these methods keep track of the number of object instances (as they are created and destroyed). + +``` +struct Result +{ +   ... +   void Result() +   { +      static int count = 0; +      Print(__FUNCSIG__, " ", ++count); +      status = "ok"; +   } +  +   void Result(string s) +   { +      static int count = 0; +      Print(__FUNCSIG__, " ", ++count); +      status = s; +   } +  +   void ~Result() +   { +      static int count = 0; +      Print(__FUNCSIG__, " ", ++count); +   } +}; + +``` + +Three static variables named count exist independently of each other: each of them counts in the context of its own function. + +As a result of running the script, we will receive the following log: + +``` +Result::Result() 1 +Result::Result() 2 +Result::Result() 3 +Result::~Result() 1 +Result::~Result() 2 +0.5 1 ok +1.00000 2.00000 3.00000 +Result::Result(string) 1 +0.5 1 ok +1.00000 2.00000 3.00000 +Result::~Result() 3 +Result::~Result() 4 + +``` + +Let's figure out, what it means. + +The first instance of the structure is created in the function OnStart, in the same line where calculate is called. When entering the constructor, the counter value count is initialized once with zero and then incremented each time the constructor is executed, so for the first time, the value 1 is output. + +Inside the calculate function, a local variable of type Result is defined; it is registered under number 2. + +The third structure instance is not so obvious. The point is that to pass the result from the function, the compiler implicitly creates a temporary variable, where it copies the data of the local variable. It is likely that this behavior will change in the future, and then the local instance will "move" out of the function without duplication. + +The last constructor call is in a method with a string parameter, so the call count is 1. + +It is important that the total number of calls to both constructors is the same as the number of calls to the destructor: 4. + +We'll talk more about [constructors](/en/book/oop/classes_and_interfaces/classes_ctors) and [destructors](/en/book/oop/classes_and_interfaces/classes_dtors) in the Chapter on Classes. diff --git a/skills/mql5/references/book/02-oop/0099-oop-structs-and-unions-structs-pack-dll.md b/skills/mql5/references/book/02-oop/0099-oop-structs-and-unions-structs-pack-dll.md new file mode 100644 index 0000000..e47856d --- /dev/null +++ b/skills/mql5/references/book/02-oop/0099-oop-structs-and-unions-structs-pack-dll.md @@ -0,0 +1,30 @@ +# Packing structures in memory and interacting with DLLs + +To store one instance of the structure, a contiguous area is allocated in memory, sufficient to fit all the elements. + +Unlike in C++, here structure elements follow one after another in memory and are not aligned on the boundary of 2, 4, 8 or 16 bytes, depending on the size of the elements themselves (alignment algorithms differ for different compilers and operating modes). Alignment of elements, the size of which is less than the specified block, is performed by adding unused dummy variables to the composition of the structure (the program does not have direct access to them). Alignment is used to optimize memory performance. + +MQL5 allows you to change the alignment rules if necessary, mainly when integrating MQL programs with third-party DLLs that describe specific types of structures. For those, it is necessary to prepare an equivalent description in MQL5 (see the section on [importing libraries](/en/book/advanced/libraries/libraries_import)). It is important to note that structures intended for integration should only have fields of a limited set of types in their definition. So, they cannot use strings, dynamic arrays, as well as class objects, and [pointers](/en/book/oop/classes_and_interfaces/classes_pointers) to class objects. + +Alignment is controlled by the keyword pack added to the header of the structure. There are two options: + +``` +struct pack(size) identifier +struct identifier pack(size) + +``` + +In both cases, the size is an integer 1, 2, 4, 8, 16. Or you can use sizeof(built-in_type) operator as the size, for example, sizeof(double). + +The option pack(1), i.e. byte alignment, is identical to default behavior without pack modifier. + +The special operator offsetof() allows you to find out the offset in bytes of a specific structure element from its beginning. It has 2 parameters: structure object and element identifier. For example, + +``` +Print(offsetof(Result, status)); // 36 + +``` + +Before the status field in the Result structure, there are 4 double values and one int value: 36 in total. + +When designing your own structures, it is recommended that you place the largest elements first, and then the rest - in order of decreasing their size. diff --git a/skills/mql5/references/book/02-oop/0100-oop-structs-and-unions-structs-composition.md b/skills/mql5/references/book/02-oop/0100-oop-structs-and-unions-structs-composition.md new file mode 100644 index 0000000..bccb3c9 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0100-oop-structs-and-unions-structs-composition.md @@ -0,0 +1,110 @@ +# Structure layout and inheritance + +Structures can have other structures as their fields. For example, let's define the Inclosure structure and use this type for the field data in the Main structure (StructsComposition.mq5): + +``` +struct Inclosure +{ +   double X, Y; +}; +  +struct Main +{ +   Inclosure data; +   int code; +}; +  +void OnStart() +{ +   Main m = {{0.1, 0.2}, -1}; // aggregate initialization +   m.data.X = 1.0;            // assignment element by element +   m.data.Y = -1.0; +} + +``` + +In the initialization list, the field data is represented by an additional level of curly brackets with field values ​​Inclosure. To access fields of such a structure, you need to use two dereference operations. + +If the nested structure is not used anywhere else, it can be declared directly inside the outer one. + +``` +struct Main2 +{ +   struct Inclosure2 +   { +     double X, Y; +   } +   data; +   int code; +}; + +``` + +Another way of laying out structures is inheritance. This mechanism is typically used for building class hierarchies (and will be discussed in detail in the corresponding [section](/en/book/oop/classes_and_interfaces/classes_inheritance)), but it is also available for structs. + +When defining a new type of structure, the programmer can indicate the type of the parent structure in its header, after the colon sign (it must be defined earlier in the source code). As a result, all fields of the parent structure will be added to the daughter structure (at its beginning), and the own fields of the new structure will be located in memory behind the parent ones. + +``` +struct Main3 : Inclosure +{ +   int code; +}; + +``` + +The parent structure here is not nested, but an integral part of the daughter structure. Because of it, filling fields does not require additional curly brackets when initializing, or a chain of multiple dereference operators. + +``` +   Main3 m3 = {0.1, 0.2, -1}; +   m3.X = 1.0; +   m3.Y = -1.0; + +``` + +All three considered structures Main, Main2, and Main3 have the same memory representation and size of 20 bytes. But they are different types. + +``` +   Print(sizeof(Main));   // 20 +   Print(sizeof(Main2));  // 20 +   Print(sizeof(Main3));  // 20 + +``` + +As we said before (see [Copying Structures](/en/book/oop/structs_and_unions/structs_assignment)), the assignment operator '=', can be used to copy related types of structures, more specifically those that are linked by an inheritance chain. In other words, a structure of a parent type can be written into a structure of a daughter type (in this case, the fields added in the derived structure will remain untouched), or vice versa, a daughter type structure can be written into a parent type structure (in this case, "extra" fields will be cut off). + +For example: + +``` +   Inclosure in = {10, 100}; +   m3 = in; + +``` + +Here, variable m3 has a type Main3 inherited from Inclosure. As a result of the assignment m3 = in, the fields X and Y (the common part for both types) will be copied from the variable in of the base type into the fields X and Y in the variable m3 of the derived type. The field code of the variable m3 will remain unchanged. + +It does not matter whether the child structure is a direct descendant of the ancestor or a distant one, i.e. the chain of inheritance can be long. Such copying of common fields works between "children", "grandchildren" and other combinations of types from different branches of the "family tree". + +If the parent structure only has constructors with parameters, it must be called from the initialization list when the derived structure constructor is inherited. For example, + +``` +struct Base +{ +   const int mode; +   string s; +   Base(const int m) : mode(m) { } +}; +  +struct Derived : Base +{ +   double data[10]; +   // if we remove the constructor, we get an error: +   Derived() : Base(1) { } // 'Base' - wrong parameters count +}; + +``` + +In the Base constructor, we fill in the field mode. Since it has the modifier const, the constructor is the only way to set a value for it, and this must be done in the form of a special initialization syntax after the colon (you can no longer assign a constant in the body of the constructor). Having an explicit constructor causes the compiler to not generate an implicit (parameterless) constructor. However, we do not have an explicit parameterless constructor in the structure Base, and in its absence, any derived class does not know how to correctly call the Base constructor with a parameter. Therefore, in the structure Derived, it is required to explicitly initialize the base constructor: this is also done using the initialization syntax in the constructor header, after the sign ':' - in this case, we call Base(1). + +If we remove the constructor Derived, we get an "invalid number of parameters" error in the base constructor, because the compiler tries to call the constructor for Base by default (which should have 0 parameters). + +We'll cover the syntax and inheritance mechanism in more detail in the [Class Chapter](/en/book/oop/classes_and_interfaces). diff --git a/skills/mql5/references/book/02-oop/0101-oop-structs-and-unions-structs-access.md b/skills/mql5/references/book/02-oop/0101-oop-structs-and-unions-structs-access.md new file mode 100644 index 0000000..6fb96f1 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0101-oop-structs-and-unions-structs-access.md @@ -0,0 +1,54 @@ +# Access rights + +If necessary, in the description of the structure, you can use special keywords, which represent access modifiers that limit the visibility of fields from outside the structure. There are three modifiers: public, protected, and private. By default, all structure members are public, which is equivalent to the following entry (using the Result structure as an example): + +``` +struct Result +{ +public: +   double probability; +   double coef[3]; +   int direction; +   string status; +   ... +}; + +``` + +All members below the modifier receive the appropriate access rights until another modifier is encountered or the structure block ends. There can be many sections with different access rights, however, they can be modified arbitrarily. + +Members marked as protected are available only from the code of this structure and descendant structures, i.e., it is assumed that they must have public methods, otherwise, no one will be able to access such fields. + +Members marked as private are accessible only from within the structure's code. For example, if you add private before the status field, you will most likely need a method to read the status by external code (getStatus). + +``` +struct Result +{ +public: +   double probability; +   double coef[3]; +   int direction; +    +private: +   string status; +    +public: +   string getStatus() +   { +      return status; +   } +   ... +}; + +``` + +It will be possible to set the status only through the parameter of the second constructor. Accessing the field directly will result in the error "no access to private member 'status' of structure 'Result'": + +``` +// error: +// cannot access to private member 'status' declared in structure 'Result' +r.status = "message"; + +``` + +In classes, the default access is private. This follows the principle of encapsulation, which we will cover in the [Chapter on Classes](/en/book/oop/classes_and_interfaces). diff --git a/skills/mql5/references/book/02-oop/0102-oop-structs-and-unions-unions.md b/skills/mql5/references/book/02-oop/0102-oop-structs-and-unions-unions.md new file mode 100644 index 0000000..29a0fa5 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0102-oop-structs-and-unions-unions.md @@ -0,0 +1,56 @@ +# Unions + +A union is a user-defined type composed of fields located in the same memory area, due to which they overlap each other. This makes it possible to write a value of one type to a union, and then read its internal representation (at the bit level) in the interpretation for another type. Thus it is possible to provide non-standard conversion from one type to another. + +Union fields can be of any built-in type, except for strings, dynamic arrays, and pointers. Also, in unions, you can use structures with the same simple field types and without constructors/destructors. + +The compiler allocates for the union a memory cell with a size equal to the maximum size among the types of all elements. So, for the union with fields like long (8 bytes) and int (4 bytes), 8 bytes will be allocated. + +All fields of the union are located at the same memory address, that is, they are aligned at the beginning of the union (they have an offset of 0, which can be checked using offsetof, see section [Packing Structures](/en/book/oop/structs_and_unions/structs_pack_dll)). + +The syntax for describing a union is similar to the structure but uses the union keyword. It is followed by an identifier and then a block of code with a list of fields. + +For example, an algorithm might use an array of type double to store various settings, simply because the type double is one of those with a maximum size in bytes equal to 8. Let's say among the settings there are numbers like ulong. Since the type double is not guaranteed to accurately reproduce large ulong values, you need to use a union to "pack" the ulong into a double and "unpack" it back. + +``` +#define MAX_LONG_IN_DOUBLE       9007199254740992 +// FYI: ULONG_MAX            18446744073709551615 +  +union ulong2double +{ +   ulong U;   // 8 bytes +   double D;  // 8 bytes +}; +ulong2double converter; +  +void OnStart() +{ +   Print(sizeof(ulong2double)); // 8 +    +   const ulong value = MAX_LONG_IN_DOUBLE + 1; +    +   double d = value; // possible loss of data due to type conversion +   ulong result = d; // possible loss of data due to type conversion +    +   Print(d, " / ", value, " -> ", result); +   // 9007199254740992.0 / 9007199254740993 -> 9007199254740992 +    +   converter.U = value; +   double r = converter.D; +   Print(r);               // 4.450147717014403e-308 +   Print(offsetof(ulong2double, U), " ", offsetof(ulong2double, D)); // 0 0 +} + +``` + +The size of the structure ulong2double is equal to 8 since both its fields have this size. Thus, the fields U and D overlap completely. + +In the realm of integers, 9007199254740992 is the largest value that is guaranteed with robust storage in double. In this example, we are trying to store one more number in double. + +The standard conversion from ulong to double results in loss of precision: after writing 9007199254740993 into a variable d of type double we read from its already "rounded" value 9007199254740992 (for additional information about the subtleties of storing numbers in the type double, see. section [Real numbers](/en/book/basis/builtin_types/float_numbers)). + +When using the converter, the number 9007199254740993 is written to the union "as is", without conversions, since we are assigning it to a U field of type ulong. Its representation in terms of double is available, again without conversions, from field D. We can copy it to other variables and arrays like double without worrying. + +Although the resulting value double looks strange, it exactly matches the original integer if it needs to be extracted by reverse conversion: write to a D field of type double, then read from a U field of type ulong. + +A union can have constructors and destructors, as well as methods. By default, union members have public access rights, but this can be adjusted using access modifiers, as in the structure. diff --git a/skills/mql5/references/book/02-oop/0103-oop-classes-and-interfaces.md b/skills/mql5/references/book/02-oop/0103-oop-classes-and-interfaces.md new file mode 100644 index 0000000..6c1e899 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0103-oop-classes-and-interfaces.md @@ -0,0 +1,23 @@ +# Classes and interfaces + +Classes are the main building block in the program development based on the OOP approach. In a global sense, the term class refers to a collection of something (things, people, formulas, etc.) that have some common characteristics. In the context of OOP, this logic is preserved: one class generates objects that have the same set of properties and behavior. + +In the previous chapters of this book, we familiarized ourselves with the built-in MQL5 types such as double, int or string. The compiler knows how to store values of these types and what operations can be performed on them. However, these types may not be very convenient to use when describing any application area. For example, a trader has to work with such entities as a trading strategy, a signal filter, a currency basket, and a portfolio of open positions. Each of them consists of a whole set of related properties, subject to specific processing and consistency rules. + +A program to automate actions with these objects could consist only of built-in types and simple functions, but then you would have to come up with tricky ways to store and link properties. This is where the OOP technology comes to the rescue, providing ready-made, unified, and intuitive mechanisms for this. + +OOP proposes to write all the instructions for storing properties, filling them correctly, and performing permitted operations on objects of a particular user-defined type in a single container with source code. It combines variables and functions in a certain way. Containers are divided into classes, structures, and associations if you list them in descending order of capabilities and relevance. + +We have already had an encounter with structures and associations in the [previous chapter](/en/book/oop/structs_and_unions). This knowledge will be useful for classes as well, but classes provide more tools from the OOP arsenal. + +By analogy with a structure, a class is a description of a user-defined type with an arbitrary internal storage method and rules for working with it. Based on it, the program can create instances of this class, the objects that should be considered composite variables. + +All user-defined types share some of the basic concepts that you might call OOP theory, but they are especially relevant for classes. These include: + +- abstraction +- encapsulation +- inheritance +- polymorphism +- composition (design) + +Despite the tricky names, they indicate quite simple and familiar norms of the real world, transferred to the world of programming. We'll start our dive into OOP by looking at these concepts. As for the syntax for describing classes and how to create objects — we will discuss it later. diff --git a/skills/mql5/references/book/02-oop/0104-oop-classes-and-interfaces-classes-abstraction.md b/skills/mql5/references/book/02-oop/0104-oop-classes-and-interfaces-classes-abstraction.md new file mode 100644 index 0000000..de9a140 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0104-oop-classes-and-interfaces-classes-abstraction.md @@ -0,0 +1,15 @@ +# OOP fundamentals: Abstraction + +We often use generalizing concepts in everyday life to convey the essence of information without going into details. For example, to answer the question "how did you get here", a person can just say "by car". And it will be clear to everyone that we are talking about a vehicle on 4 wheels, with an engine and a body for passengers. The specific brand, the color or the year of manufacture of the car does not matter to us. + +When working with the program, the user also does not really care what kind of algorithm is implemented inside, as long as the program correctly performs its task. For example, sorting a list can be done in a dozen different ways. + +Thus, abstraction means providing a simple programming interface that leaves hidden all the complexities and details of the implementation. + +The programming interface is a set of functions that are defined in the context of a class and that perform a set of actions according to the purpose of the objects. In addition to these interface functions, there may be auxiliary, smaller functions, but they are available only inside the class. Similar to structures, there is a special name for all functions of a class: they are called methods. + +The implementation, as a rule, uses variables or arrays belonging to the object (according to the class description) to store information. They are called 'fields' (this term comes from the fact that object properties are often associated in a 1:1 relationship with input fields in the user interface, or with fields in databases, where the current state of the object can be saved so that it can be restored the next time the program is launched). + +Fields and methods, although described in the class, are related to a specific object: each instance has its own allocated set of variables, they have values that are independent of the state of other objects, and the methods work with the fields of their instance. + +Interface and implementation must be independent. If desired, one implementation method should be easy to replace with another without any impact on the programming interface. It is also very important to design the interface based on the requirements of a particular task, and not to customize it specifically for the implementation. The class developer must be able to view their creation from two different points of view: 1) as the author of internal algorithms and data structures; 2) as a potential picky customer who uses the class as a "black box" and its control panel is the interface. It is recommended to start developing a class from thinking through the programming interface to finding and choosing the implementation methods. diff --git a/skills/mql5/references/book/02-oop/0105-oop-classes-and-interfaces-classes-encapsulation.md b/skills/mql5/references/book/02-oop/0105-oop-classes-and-interfaces-classes-encapsulation.md new file mode 100644 index 0000000..d03a94e --- /dev/null +++ b/skills/mql5/references/book/02-oop/0105-oop-classes-and-interfaces-classes-encapsulation.md @@ -0,0 +1,13 @@ +# OOP fundamentals: Encapsulation + +To understand what encapsulation is, let's go back to reality for a moment. When we purchase a household appliance, it is usually "sealed" and under warranty. We are allowed to use it in normal modes, but the manufacturer does not encourage us to open the case and start "digging inside". For example, you can use special utilities to overclock the computer processor, but this also deprives us of the warranty, because these actions can lead to equipment failure. + +It is all the same with the development of classes. Nobody should be allowed to access internal implementation, so as not to disrupt the class. This is called encapsulation, that is, including everything important in a capsule. In MQL5, as in C++, there are 3 levels of access rights. By default, the class organization is private, i.e. hidden from all its users. Only the source code of the class itself has access to the content. + +Class users are also programmers. Even if you're writing a class for yourself, it makes sense to take advantage of the maximum restrictions so as not to accidentally break the class (after all, people tend to make mistakes and forget the features of their own code after a while, and programs have a tendency to grow indefinitely). + +The second level of access allows the "relatives" (more precisely, the heirs; we will come back to them in a couple of paragraphs) to take a look inside. + +Finally, the third level of access that you can choose is public. It is intended specifically for external programming interfaces that allow objects to be used from any part of the program for their main purpose. + +Each method or field has one of three access levels, which is determined by the class developer. diff --git a/skills/mql5/references/book/02-oop/0106-oop-classes-and-interfaces-classes-oop-inheritance.md b/skills/mql5/references/book/02-oop/0106-oop-classes-and-interfaces-classes-oop-inheritance.md new file mode 100644 index 0000000..67a2268 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0106-oop-classes-and-interfaces-classes-oop-inheritance.md @@ -0,0 +1,21 @@ +# OOP fundamentals: Inheritance + +When building large and complex projects, people seek ways to make the process more efficient. One of the popular ways is leveraging existing developments. For example, it is much easier to develop a building plan not from scratch but based on the previous blueprints. + +Code reuse in programming is also very popular. We already know one such technique: isolating a piece of code into a function and then calling it from different places where the corresponding functionality is required. But OOP provides a more powerful mechanism: when developing a new class, it can inherit from another, acquiring all the internal structure and external interface, requiring only minimum adjustment to suit the purpose. Thus, starting from the parent class, you can quickly "grow" a derived class with additional or refined abilities. Also, any subsequent changes to the parent class (such as enhancements or bug fixes) will automatically affect all child classes. + +When a class is the parent of another, it is referred to as the base class. In turn, the class that is inherited from the base class is called derived. + +Of course, the chain of inheritance (or rather, the family tree) can be continued: each class can have several heirs, those, in turn, have their heirs, and so on. The only thing that inheritance rules do not allow is cycles in kinship relationships, for example, a grandson cannot be the parent of its grandfather. + +The relationship between any class and its descendant of any generation is described by the word "is a", that is, the descendant is able to act as an ancestor, but not vice versa. This is because the derived object actually contains the data model of the ancestor and supplements it with new fields and behavior. + +By inheriting classes from each other, we get the opportunity to process related objects in a unified way, as some of their functions are common. + +For example, a hypothetical drawing program can be used to implement several types of shapes, including circles, squares, triangles, and so on. Each object has coordinates on the screen (for simplicity, we will assume that a pair of X and Y values of the shape center is specified). In addition, each shape is rendered using its own background color, border color, and border thickness. + +This means that we can implement functions for setting the coordinates and setting the drawing style only once in the parent class describing the abstract shape, and these functions will be automatically inherited by all the descendants. + +Moreover, in order to simplify the source code, it is desirable to somehow unify not only the settings but also the drawing of different shapes. This phrase contains some kind of contradiction: since the shapes are different, and each must be displayed in its own way, what kind of unification are we talking about? We're talking about a unified software interface. Indeed, according to the concept of abstraction, it is necessary to separate the external interface from the internal implementation. And the display of specific shapes is essentially an implementation detail. + +A unified interface and different implementations for shape types smoothly lead us to the next concept — polymorphism. diff --git a/skills/mql5/references/book/02-oop/0107-oop-classes-and-interfaces-classes-polymorphism.md b/skills/mql5/references/book/02-oop/0107-oop-classes-and-interfaces-classes-polymorphism.md new file mode 100644 index 0000000..4853122 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0107-oop-classes-and-interfaces-classes-polymorphism.md @@ -0,0 +1,11 @@ +# OOP fundamentals: Polymorphism + +The term polymorphism means variability or diversity. This is the inverse of abstraction combined with the inheritance mechanism. When we have a common programming interface, it can be implemented by different classes which are linked by relations of inheritance. Then calling interface methods will cause the task to be performed in different ways. + +For example, imagine a family of abstract vehicles that includes a couple of certain types: a car and a helicopter. The command to move from point A to point B will be executed by them equally well, but the car will make its way on the ground, and the helicopter in the air. + +Let's continue the example with the drawing program. We can say that the diversity in it is laid down at the level of graphic shapes. The user is free to draw any combination of circles, squares, and triangles. Each of these objects must be able to display itself on the screen using its own coordinates and its own style, but the most important thing is to do it in a way that produces an appropriate form. + +The program will most likely have an array (or another container) that stores all the shapes created by the user, and displaying the entire drawing on the screen should consist in sequentially drawing each shape. If we reduce drawing instructions for shapes into a separate method (let's call it draw), then each class will have its own implementation. However, the headers of these functions will be completely identical, since they perform the same task, and take the initial data from the objects. + +Therefore, we have the opportunity to unify the source code, since the same call to draw inside the loop over shapes exhibits polymorphism: the displayed shape will depend on the type of object. diff --git a/skills/mql5/references/book/02-oop/0108-oop-classes-and-interfaces-classes-composition.md b/skills/mql5/references/book/02-oop/0108-oop-classes-and-interfaces-classes-composition.md new file mode 100644 index 0000000..794f60f --- /dev/null +++ b/skills/mql5/references/book/02-oop/0108-oop-classes-and-interfaces-classes-composition.md @@ -0,0 +1,25 @@ +# OOP fundamentals: Composition (design) + +When designing programs using OOP, there is a problem of finding the optimal (according to some given characteristics) division into classes and relations between them. The term "composition" can be ambiguous and is often used with different meanings, including one of the special cases of "composing" classes. This digression is necessary because when reading other computer literature, you can find different interpretations of the term "compositions": both in a generalized and in a narrower sense. We will try to explain this concept, specifying the meaning of the terms in each case (when it means the general "design/project development" of the software interface, and when it means "compositional aggregation"). + +So, the class, as we know, consists of fields (properties) and methods. Properties, in turn, can be described by custom types, that is, they can be objects of another class. There are several ways to logically connect these objects: + +- Composition (full inclusion or compositional aggregation) of objects-fields into an owner object. The relationship of such objects is described by the "whole-part" relationship, and the part cannot exist outside the whole. The owner object is said to "have a" property object, and the property object is a "part of" the owner object. The owner creates and destroys its parts. Deleting the owner removes all of its parts; the owner cannot exist without parts. +- Aggregation of objects-fields by the owner object is a "softer" inclusion. Although the relationship is also described as "whole-part", the owner only contains references to parts that can be assigned, changed, and exist in isolation from the whole. Moreover, one part can be used in several "owners". +- Association, that is, a one- or two-way connection of independent objects that has an arbitrary applied meaning; one object is said to "use" another. + +Another type of relationship to keep in mind is "is a", discussed earlier in the [inheritance](/en/book/oop/classes_and_interfaces/classes_oop_inheritance) section. + +An example of a full inclusion is a car and its engine. Here, a car is understood as a full-fledged means of transportation. It's not like that without a motor. And a particular engine belongs to only one car at a time. Situations when there is no engine in the car yet (at the factory) or it no longer exists (in the car repair shop) are equivalent to the fact that we broke the source code of the program. + +An example of aggregation is the composition of groups of students for studies of certain courses: a group for each course includes several students, and any of them can belong to other groups (if listening to several subjects). The group "has" listeners. The exit of a student from the group does not affect the educational process of the group (the rest continue to study). + +Finally, to demonstrate the idea of association, consider a computer and a printer. We can say that the computer uses the printer to print. The printer can be turned on or off as needed, and the same printer can be used from different computers. All computers and printers exist independently of each other but can be shared. + +As for the characteristics that are customary to guide the design of classes, the most famous include: + +- DRY (Don't repeat yourself) — instead, move common parts into parent (possibly abstract) classes. +- SRP (Single Responsibility Principle) — one class should perform one task, and if this is not the case, you need to split it into smaller ones. +- OCP (Open-Closed Principle) — "write code open for extension but closed for modification". If several calculation options are hardcoded in the X class and new ones may appear, make a base (abstract) class for a separate calculation and create specific options ("extension" of the functionality) on its basis, connected to class X without modifying it. + +These are just a few of the class design best practices. After mastering the basics of OOP within the scope of this book, it may be helpful to look at other specialized sources of information on the topic, as they provide ready-made solutions for object decomposition in many common situations. diff --git a/skills/mql5/references/book/02-oop/0109-oop-classes-and-interfaces-classes-definition.md b/skills/mql5/references/book/02-oop/0109-oop-classes-and-interfaces-classes-definition.md new file mode 100644 index 0000000..dc865d6 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0109-oop-classes-and-interfaces-classes-definition.md @@ -0,0 +1,117 @@ +# Class definition + +The class definition statement has many optional components that affect its characteristics. In a generalized form, it can be represented as follows: + +``` +class class_name [: modifier_access name_parent_class ...] +{ +  [ modifier_access:] +     [description_member...] +  ... +}; + +``` + +To make the presentation easier, we will start with the minimum sufficient syntax and will expand it as we move through the material. + +As a starting ground, we use a task with a conditional drawing program that supports several types of shapes. + +To define a new class, use the class keyword, followed by the class identifier and a block of code in curly brackets. Like all statements, such a definition must end with a semicolon. + +The code block can be empty. For example, a compilable template of class Shape for a drawing program looks like this: + +``` +class Shape +{ +}; + +``` + +From the previous chapters of the book, we know that curly brackets denote the context or scope of variables. When such blocks occur in a function definition, they define its local context. In addition to it, there is a global context in which the functions themselves are defined, as well as global variables. + +This time, the parentheses in the class definition define a new kind of context, the class context. It is a container for both variables and functions declared inside the class. + +The description of variables for storing class properties is done by the usual statements inside the block (Shapes1.mq5). + +``` +class Shape +{ +   int x, y;              // center coordinates +   color backgroundColor; // fill color +}; + +``` + +Here we have declared some of the fields discussed in the theoretical sections: the coordinates of the shape center and the fill color. + +After such a description, the user-defined type Shape becomes available in the program along with the built-in types. In particular, we can create a variable of this type, and it will contain the specified fields inside. However, we cannot yet do anything with them and even make sure that they are there. + +``` +void OnStart() +{ +   Shape s; +   // errors: cannot access private member declared in class 'Shape' +   Print(s.x, " ", s.y); +} + +``` + +Class members are private by default, and therefore cannot be accessed from other parts of the code external to the class. This is the principle of encapsulation in action. + +If we try to output a shape to the log, the result will disappoint us for several reasons. + +The most straightforward approach will cause the "objects are only passed by reference" error (we've seen this with structures too): + +``` +Print(s); // 's' - objects are passed by reference only + +``` + +Objects may consist of many fields, and because of their large size, it is inefficient to pass them by value. Therefore, the compiler requires object type parameters to be passed by reference, while Print takes values. + +From the section about function parameters (see section [Value parameters and reference parameters](/en/book/basis/functions/functions_ref_value)), we know that the symbol '&' is used to describe references. It would be logical to assume that in order to obtain a reference to a variable (in this case, an object s of type Shape) it is necessary to put the same sign before its name. + +``` +Print(&s); + +``` + +This statement compiles and runs without problem but does not quite do what was expected. + +The program outputs some integer number during execution, for example, 1 or 2097152 (it will most likely be different). An ampersand sign in front of a variable name means getting a pointer to this variable, not a reference (as opposed to a function parameter description). + +[Pointers](/en/book/oop/classes_and_interfaces/classes_pointers) will be discussed in detail in a separate section. However, note that MQL5 does not provide direct access to memory, and the pointer to an object is a descriptor, or in a simple way, a unique object number (it is assigned by the terminal itself). But even if the pointer pointed to an address in memory (as it does in C++), that would not provide a legal way to read the object's contents. + +To output the contents of Shape objects to the log or whatever, a class member function is required. Let's call it toString: it should return a string with some description of the object. We can decide later what to display in it. Let's also reserve the draw method for drawing the shape. For now, it will act as a declaration of the future object programming interface. + +``` +class Shape +{ +   int x, y;              // center coordinates +   color backgroundColor; // fill color +    +   string toString() +   { +      ... +   } +    +   void draw() { /* future drawing interface stub */ } +}; + +``` + +The definition of method functions is done in the usual way, with the only difference being that they are located inside the block of code that forms the class. + +In the future, we will learn how to separate the declaration of a function inside the class block and its [definition outside the block](/en/book/oop/classes_and_interfaces/classes_declaration_definition). This approach is often used to put declarations in a header file and "hide" definitions in an mq5 file. This makes the code more understandable (due to the fact that the programming interface is presented separately, in a compact form, without implementation). It also allows [software libraries](/en/book/advanced/libraries) to be distributed as ex5 files if needed (without the main source code but providing a header file that is sufficient to call the external interface methods). + +Because the method toString is part of the class, it has access to variables and can convert them to a string. For example, + +``` +string toString() +{ +  return (string)x + " " + (string)y; +} + +``` + +However, now toString and draw are private, as are the rest of the fields. We need to make them available from outside the class. diff --git a/skills/mql5/references/book/02-oop/0110-oop-classes-and-interfaces-classes-access-rights.md b/skills/mql5/references/book/02-oop/0110-oop-classes-and-interfaces-classes-access-rights.md new file mode 100644 index 0000000..3cea103 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0110-oop-classes-and-interfaces-classes-access-rights.md @@ -0,0 +1,79 @@ +# Access rights + +A special syntax is provided for editing access to class members (we already met it in the chapter on structures). Anywhere in the block, before the description of class members, you can insert a modifier: one of the three keywords – private, protected, public – and a colon sign. + +All members following the modifier, until another modifier is encountered, or up to the end of the class, will receive the corresponding visibility constraint. + +For example, the following entry is identical to the previous description of the class Shape, because the mode private is assumed for classes without modifiers: + +``` +class Shape +{ +private: +   int x, y;              // center coordinates +   color backgroundColor; // fill color +   ... +}; + +``` + +If we wanted to open access to all fields, we would change the modifier to public + +``` +class Shape +{ +public: +   int x, y;              // center coordinates +   ... +}; + +``` + +But that would violate the principle of encapsulation, and we won't do that. Instead, we insert the modifier protected: it allows access to members from derived classes while leaving them hidden from the outside world. We are planning to extend the class Shape to several other shape classes that will need access to the parent's variables. + +``` +class Shape +{ +protected: +   int x, y;              // center coordinates +   color backgroundColor; // fill color +    +public: +   string toString() const +   { +      return (string)x + " " + (string)y; +   } +    +   void draw() { /* shape drawing interface stub */ } +}; + +``` + +Along the way, we made both functions public. + +Modifiers can be interleaved in the class description in an arbitrary way and repeated many times. However, in order to improve the readability of the code, it is recommended to make one section of public, protected, and private members, and withstand the same order in all classes of the project. + +Note that we added the keyword const to the end of the header of the toString function. It means that the function does not change the state of the object fields. Although not required, it helps prevent accidental corruption of variables and also lets users of the class and the compiler know that calling the function will not result in any side effects. + +In the toString function, as in any class method, the fields are accessible by their names. Later, we'll see how to declare [methods as static](/en/book/oop/classes_and_interfaces/classes_static): they are related entirely to the class, not to object instances, and therefore fields cannot be accessed. + +Now we can call the method toString from the object variable s: + +``` +void OnStart() +{ +   Shape s; +   Print(s.toString()); +} + +``` + +Here we see the use of the dot character '.' as a special dereference operator: it provides access to the members of the object — fields and methods. To the left of it should be an object, and to the right — the identifier of one of the available properties. + +The method toString is public, and therefore accessible from an external to the class function OnStart. If we tried in OnStart to "reach out" to the fields s.x or s.y through dereference, we would get a compilation error "cannot access protected member declared in class 'Shape'". + +For C++ professionals, we note that MQL5 does not support so-called "friends" (for the rest, let's explain that in C++ it is possible, if necessary, to make a kind of "whitelist" of third-party classes and methods that have extended rights, although they are not "relatives"). + +When we run the program, we will see that it outputs a couple of numbers. However, the coordinate values will be random. Even if you are lucky enough to see nulls, it does not guarantee that they will appear the next time you run the script. As a rule, if the list of executing MQL programs does not change in the terminal, repeated launches of any script result in the allocation of the same memory area to it, which may give the deceptive impression that the state of the object is stable. In fact, the fields of an object, as in the case of local variables, are not initialized with anything by default (see section [Initialization](/en/book/basis/variables/initialization)). + +To initialize them, special class functions, constructors, are used. diff --git a/skills/mql5/references/book/02-oop/0111-oop-classes-and-interfaces-classes-ctors.md b/skills/mql5/references/book/02-oop/0111-oop-classes-and-interfaces-classes-ctors.md new file mode 100644 index 0000000..4e57844 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0111-oop-classes-and-interfaces-classes-ctors.md @@ -0,0 +1,221 @@ +# Constructors: default, parametric, and copying + +We have already encountered constructors in the chapter on structures (see section [Constructors and destructors](/en/book/oop/structs_and_unions/structs_ctor_dtor)). For classes, they work in much the same way. Let's get back to the main points and consider further features. + +A constructor is a method having the same name as the class and is of type void, meaning it does not return a value. Usually, the keyword void is omitted before the constructor name. A class can have several constructors: they must differ in the number or type of parameters. When a new object is created, the program calls the constructor so that it can set the initial values for the fields. + +One of the ways to create an object that we used is the description in the code of the variable of the corresponding class. The constructor will be called on this string. It happens automatically. + +Depending on the presence and types of parameters, constructors are divided into: + +- default constructor: no parameters; +- copy constructor: with a single parameter which is the type of a reference to an object of the same class; +- parametric constructor: with an arbitrary set of parameters, except for a single reference for copying shown above. + +Default constructor + +The simplest constructor, without parameters, is called the default constructor. Unlike C++, MQL5 does not consider a default constructor to be a constructor that has parameters and all of them have default values ​​(that is, all parameters are optional, see section [Optional parameters](/en/book/basis/functions/functions_parameters_default)). + +Let's define a default constructor for the class Shape. + +``` +class Shape +{ +   ... +public: +   Shape() +   { +      ... +   } +}; + +``` + +Of course, it should be done in the public section of the class. + +Constructors are sometimes deliberately made protected or private to control how objects are created, for example, through factory methods. But in this case, we are considering the standard version of class composition. + +To set initial values for object variables, we could use the usual assignment statements: + +``` +public: +   Shape() +   { +      x = 0; +      y = 0; +      ... +   } + +``` + +However, the constructor syntax provides another option. It is called the initialization list and is written after the function header, separated by a colon. The list itself is a comma-separated sequence of field names, with the desired initial value in parentheses to the right of each name. + +For example, for the constructor Shape it can be written as follows: + +``` +public: +   Shape() : +      x(0), y(0), +      backgroundColor(clrNONE) +   { +   } + +``` + +This syntax is preferred over assigning variables in the body of a constructor for several reasons. + +First, the assignment in the function body is made after the corresponding variable has been created. Depending on the type of the variable, this may mean that the default constructor was first called for it and then the new value was overwritten (and this means extra expenses). In the case of an initialization list, the variable is immediately created with the desired value. It is likely that the compiler will be able to optimize the assignment in the absence of an initialization list, but in the general case, this is not guaranteed. + +Secondly, some class fields can be declared with the const modifier. Then they can only be set in the initialization list. + +Thirdly, field variables of user-defined types may not have a default constructor (that is, all available constructors in their class have parameters). This means that when you create a variable, you need to pass actual parameters to it, and the initialization list allows you to do this: the argument values are specified inside parentheses, as if in an explicit constructor call. An initialization list can be used in constructor definitions, but not in other methods. + +Parametric constructor + +A parametric constructor, by definition, has multiple parameters (one or more). + +For example, imagine that for coordinates x and y a special structure with a parametric constructor is described: + +``` +struct Pair +{ +   int x, y; +   Pair(int a, int b): x(a), y(b) { } +}; + +``` + +Then we can use the coordinates field of the new type Pair instead of the two integer fields x and y in the Shape class. This construction of objects is called inclusion or compositional aggregation. The Pair object is an integral part of the object Shape. A coordinate pair is automatically created and destroyed along with the "host" object. + +Because Pair does not have a parameterless constructor, the coordinates field must be specified in the initialization list of the Shape constructor, with two parameters (int, int): + +``` +class Shape +{ +protected: +   // int x, y; +   Pair coordinates;  // center coordinates (object inclusion) +   ... +public: +   Shape() : +      // x(0), y(0), +      coordinates(0, 0), //object initialization +      backgroundColor(clrNONE)  +   { +   } +}; + +``` + +Without an initialization list, such automatic objects cannot be created. + +Given the change in how coordinates are stored in the object, we need to update the toStringmethod: + +``` +   string toString() const +   { +      return (string)coordinates.x + " " + (string)coordinates.y; +   } + +``` + +But this is not the final version: we will make some more changes soon. + +Recall that automatic variables were described in the [Declaration/Definition Instructions](/en/book/basis/statements/statements_declaration) section. They are called automatic because the compiler creates them (allocates memory) automatically, and also automatically deletes them when program execution leaves the context (block of code) in which the variable was created. + +  + +In the case of object variables, automatic creation means not only memory allocation but also a constructor call. The automatic deletion of an object is accompanied by a call to its destructor (see below section [Destructors](/en/book/oop/classes_and_interfaces/classes_dtors)). Moreover, if the object is part of another object, then its lifetime coincides with the lifetime of its "owner", as in the case of the field coordinates – an instance of Pair in the object Shape. + +  + +Static (including global) objects are also managed automatically by the compiler. + +  + +An alternative to automatic allocation is [dynamic object creation and manipulation via pointers](/en/book/oop/classes_and_interfaces/classes_new_delete_pointers). + +In the [inheritance](/en/book/oop/classes_and_interfaces/classes_inheritance) section, we will learn how one class can be inherited from another. In this case, the initialization list is the only way to call the parametric constructor of the base class (the compiler is not able to automatically generate a constructor call with parameters, as it does implicitly for the default constructor). + +Let's add another constructor to the class Shape that allows you to set specific values ​​to variables. It will just be a parametric constructor (you can create as many of them as you like: for different purposes and with a different set of parameters). + +``` +   Shape(int px, int py, color back) : +      coordinates(px, py), +      backgroundColor(back) +   { +   } + +``` + +The initialization list ensures that when the body of the constructor is executed, all internal fields (including nested objects, if any) have already been created and initialized. + +The order of initialization of class members does not correspond to the initialization list but to the sequence of their declaration in the class. + +If a constructor with parameters is declared in a class, and it is required to allow the creation of objects without arguments, the programmer must explicitly implement the default constructor + +In the event that there are no constructors at all in the class, the compiler implicitly provides a default constructor in the form of a stub, which is responsible for initializing fields of the following types: strings, dynamic arrays, and automatic objects with a default constructor. If there are no such fields, the implicit default constructor does nothing. Fields of other types are not affected by the implicit constructor, so they will contain random "garbage". To avoid this, the programmer must explicitly declare the constructor and set the initial values. + +Copy constructor + +The copy constructor allows you to create an object based on another object passed by reference as the only parameter. + +For example, for the class Shape, the copy constructor might look like this: + +``` +class Shape +{ +   ... +   Shape(const Shape &source) : +      coordinates(source.coordinates.x, source.coordinates.y), +      backgroundColor(source.backgroundColor) +   { +   } +   ... +}; + +``` + +Note that protected and private members of another object are available in the current object because permissions work at the class level. In other words, two objects of the same class can access each other's data when given a reference (or [pointer](/en/book/oop/classes_and_interfaces/classes_new_delete_pointers)). + +If there is such a constructor, you can create objects using one of two syntax types: + +``` +void OnStart() +{ +   Shape s; +   ... +   Shape s2(s);   // ok: syntax 1 - copying +   Shape s3 = s;  // ok: syntax 2 - copying via initialization +                  //                   (if there is copy constructor) +                  //                 - or assignment +                  //                   (if there is no copy constructor, +                  //                    but there is default constructor) +    +   Shape s4;      // definition +   s4 = s;        // assignment, not copy constructor! +} + +``` + +It is necessary to distinguish between initialization of an object during creation and assignment. + +The second option (marked with the "syntax 2" comment) will work even if there is no copy constructor, but there is a default constructor. In this case, the compiler will generate less efficient code: first, using the default constructor, it will create an empty instance of the receiving variable (s3, in this case), and then copy the fields of the sample (s, in this case) element by element. In fact, the same case will turn out as with the variable s4, for which the definition and assignment are performed by separate statements. + +If there is no copy constructor, then attempting to use the first syntax will result in a "parameter conversion not allowed" error, as the compiler will try to take some other constructor available with a different set of parameters. + +Keep in mind that if the class has fields with the modifier const, assigning such objects is prohibited for obvious reasons: a constant field cannot be changed, it can only be set once when creating an object. Therefore, the copy constructor becomes the only way to duplicate an object. + +In particular, in the following sections, we will complete our Shape1.mq5 example, and the following field will appear in the Shape class (with a description string type). Then the assignment operator will generate errors (in particular, for such lines as with the variable s4): + +``` +attempting to reference deleted function +   'void Shape::operator=(const Shape&)' +function 'void Shape::operator=(const Shape&)' was implicitly deleted +   because member 'type' has 'const' modifier + +``` + +Thanks to the detailed wording of the compiler, you can understand the essence and reasons for what is happening: first, the assignment operator ('=') is mentioned, and not the copy constructor; second, it is reported that the assignment operator was implicitly removed due to the presence of the modifier const. Here we encounter concepts that are yet unknown, which we will study later: [operator overloading in classes](/en/book/oop/classes_and_interfaces/classes_operator_overloading), [object type conversion](/en/book/oop/classes_and_interfaces/classes_dynamic_cast_void), and the ability to mark methods as [deleted](/en/book/oop/classes_and_interfaces/classes_final_delete). + +In the section [Inheritance](/en/book/oop/classes_and_interfaces/classes_inheritance), after we learn how to describe derived classes, we need to make some clarifications about copy constructors in class hierarchies. diff --git a/skills/mql5/references/book/02-oop/0112-oop-classes-and-interfaces-classes-dtors.md b/skills/mql5/references/book/02-oop/0112-oop-classes-and-interfaces-classes-dtors.md new file mode 100644 index 0000000..15b3ce0 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0112-oop-classes-and-interfaces-classes-dtors.md @@ -0,0 +1,52 @@ +# Destructors + +In the chapter on structures, we learned about destructors (see the section about [Constructors and destructors](/en/book/oop/structs_and_unions/structs_ctor_dtor)). Let's briefly recap: a destructor is a method that is called when an object is destroyed. The destructor shares the same name as the class but is prefixed with a tilde character (~). Destructors do not return values and do not have any parameters. A class can only have one destructor. + +Even if the class has no destructor or the destructor is empty, the compiler will implicitly perform "garbage collection" of the following types of fields: strings, dynamic arrays, and automatic objects. + +Usually, the destructor is placed in the public section of the class, however, in some specific cases, the developer can move it to a group of private or protected members. A private or protected destructor will not allow you to declare an automatic variable of this class in the code. However, we will see [dynamic object creation](/en/book/oop/classes_and_interfaces/classes_new_delete_pointers) a little later, and for them, such a restriction might make sense. + +In particular, some objects can be implemented in such a way that they must delete themselves when they are no longer needed (the concept of determining demand may be different). In other words, while objects are used by any part of the program, they exist, and as soon as the task is completed, they are self-destructed (a private destructor leaves the possibility to delete the object from class methods). + +For experienced C++ programmers, it is worth noting that destructors are always virtual in MQL5 (more on virtual methods will be covered in the section about [Virtual methods (virtual and override)](/en/book/oop/classes_and_interfaces/classes_virtual_override)). This factor does not affect the syntax of the description. + +In the example of the drawing program, technically, a destructor may not be necessary for shapes. However, for the purpose of tracing the sequence of calls to constructors and destructors, we will include one. Let's start with a simplified outline that "prints" the full name of the method: + +``` +class Shape +{ +   ... +   ~Shape() +   { +      Print(__FUNCSIG__); +   } +}; + +``` + +We will soon add to this and other methods so that we can distinguish one instance of an object from another. + +Consider the following example. A pair of objects Shape are described in two different contexts: global (outside functions) and local (inside OnStart). The global object constructor will be called after the script is loaded and before OnStart is called, and the destructor will be called before the script is unloaded. The local object's constructor will be called in the line with the variable definition, and the destructor will be called when the code block containing the variable definition exits, in this case the function OnStart. + +``` +// the global constructor and destructor are related to script loading and unloading +Shape global; +  +// object reference does not create a copy and does not affect lifetime +void ProcessShape(Shape &shape) +{ +   // ... +} +  +void OnStart() +{ +   // ... +   Shape local; // <- local constructor call +   // ... +   ProcessShape(local); +   // ... +} // <- local destructor call + +``` + +Passing an object by reference to other functions does not create copies of it and does not call the constructor and destructor. diff --git a/skills/mql5/references/book/02-oop/0113-oop-classes-and-interfaces-classes-this.md b/skills/mql5/references/book/02-oop/0113-oop-classes-and-interfaces-classes-this.md new file mode 100644 index 0000000..b3ded39 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0113-oop-classes-and-interfaces-classes-this.md @@ -0,0 +1,114 @@ +# Self-reference: this + +In the context of each class, in its methods code, there is a special reference to the current object: this. Basically, it is an implicitly defined variable. All the methods of working with object variables are applicable to it. In particular, it can be dereferenced to refer to an object field or to call a method. For example, the following statements in a method of the Shape class are identical (we use the draw method for demonstration purposes only): + +``` +class Shape +{ +   ... +   void draw() +   { +      backgroundColor = clrBlue; +      this.backgroundColor = clrBlue; +   } +}; + +``` + +It might be necessary to use the long form if there are other variables/parameters with the same name in the same context. This practice is generally not welcomed, but if necessary, the keyword this allows you to refer to the overridden members of an object. + +The compiler issues a warning if the name of any local variable or method parameter overlaps the name of a class member variable. + +In the following hypothetical example, we have implemented the draw method, which takes an optional string parameter backgroundColor with the color name. Because the parameter name is the same as the class member Shape, the compiler issues the first warning "the definition of 'backgroundColor' hides the field". + +The consequence of the overlap is that the subsequent erroneous assignment of the clrBlue value works on the parameter and not on the class member, and because the value and parameter types do not match, the compiler will issue a second warning, "implicit number to string conversion" (the number here is a constant clrBlue). But the line this.backgroundColor = clrBlue writes the value to the field of the object. + +``` +   void draw(string backgroundColor = NULL) //warning 1: +                // declaration of 'backgroundColor' hides member +   { +      ... +      backgroundColor = clrBlue; // warning 2: +        // implicit conversion from 'number' to 'string' +      this.backgroundColor = clrBlue; // ok +       +      { +         bool backgroundColor = false; // warning 3: +             // declaration of 'backgroundColor' hides local variable +         ... +         this.backgroundColor = clrRed; // ok +      } +      ... +   } + +``` + +The subsequent definition of the local boolean variable backgroundColor (in the nested block of curly brackets) overrides the previous definitions of that name once again (which is why we get the third warning). However, by dereferencing this, the statement this.backgroundColor = clrRed also refers to an object field. + +Without this specified, the compiler always chooses the closest (by context) name definition. + +There is also a need for this of another kind: to pass the current object as a parameter to another function. In particular, an approach is taken in which objects of the same class are responsible for creating/deleting objects of another class, and the subordinate object must know its "boss". Then the dependent objects are created in the "boss" class using the constructor, and this of the "boss" object is passed into it. This technique typically uses dynamic object allocation and pointers, and due to this a relevant example will be shown in the section [pointers](/en/book/oop/classes_and_interfaces/classes_pointers). + +Another common use of this is to return a pointer to the current object from a member function. This allows you to arrange member function calls in a chain. As we have yet to study pointers in detail, it will be enough to know that a pointer to an object of some class is described by adding the character '*' to the class name, and you can work with an object through a pointer in the same way as you would do directly. + +For example, we can provide the user with several methods to set the properties of a shape individually: change color, move horizontally or vertically. Each of them will return a pointer to the current object. + +``` +   Shape *setColor(const color c) +   { +      backgroundColor = c; +      return &this; +   } +    +   Shape *moveX(const int x) +   { +      coordinates.x += x; +      return &this; +   } +  +   Shape *moveY(const int y) +   { +      coordinates.y += y; +      return &this; +   } + +``` + +Then it is possible to conveniently arrange calls to these methods in a chain. + +``` +   Shape s; +   s.setColor(clrWhite).moveX(80).moveY(-50); + +``` + +When there are many properties in a class, this approach allows you to compactly and selectively configure an object. + +In the section [Class definition](/en/book/oop/classes_and_interfaces/classes_definition), we tried to log an object variable but discovered that we could use its name with only an ampersand (in a Print call) to get a pointer, or, in fact, a unique number (handle). In an object context, the same handle is available via &this. + +For debugging purposes, you can identify objects by their descriptor. We're going to explore class inheritance, and when there is more than one of those, identification will come in handy. Because of it, in all constructors and destructors, we add (and will add in the future in derived classes) the following Print call: + +``` +   ~Shape() +   { +      Print(__FUNCSIG__, " ", &this); +   } + +``` + +Now all creation and deletion steps will be marked in the log with the class name and object number. + +We implement similar constructors and destructors in the Pair structure, however in structures, unfortunately, pointers are not supported, i.e. writing &this is impossible. Therefore, we can identify them only by their content (in this case, by their coordinates): + +``` +struct Pair +{ +   int x, y; +   Pair(int a, int b): x(a), y(b) +   { +      Print(__FUNCSIG__, " ", x, " ", y); +   } +   ... +}; + +``` diff --git a/skills/mql5/references/book/02-oop/0114-oop-classes-and-interfaces-classes-inheritance.md b/skills/mql5/references/book/02-oop/0114-oop-classes-and-interfaces-classes-inheritance.md new file mode 100644 index 0000000..e19e331 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0114-oop-classes-and-interfaces-classes-inheritance.md @@ -0,0 +1,263 @@ +# Inheritance + +When defining a class, a developer can inherit it from another class, thereby embodying the [concept of inheritance](/en/book/oop/classes_and_interfaces/classes_oop_inheritance). To do this, the class name is followed by a colon sign, an optional access rights modifier (one of the keywords public, protected, private), and the name of the parent class. For example, here's how we can define a class Rectangle that derives from Shape: + +``` +class Rectangle : public Shape +{ +}; + +``` + +Access modifiers in the class header control the "visibility" of the members of the parent class included in the child class: + +- public — all inherited members retain their rights and limitations +- protected — changes the rights of inherited public members to protected +- private — makes all inherited members private (private) + +The modifier public is used in the vast majority of definitions. The other two options make sense only in exceptional cases because they violate the basic principle of inheritance: objects of a derived class should be "is a" – full-fledged representatives of the parent family, and if we "truncate" their rights, they lose part of their characteristics. Structures can also be inherited from each other in a similar way. It is forbidden to inherit classes from structures or structures from classes. + +Unlike C++, MQL5 does not support multiple inheritance. A class can have at most one parent. + +A derived class object has a base class object built into it. Considering that the base class can, in turn, be inherited from some other parent class, the created object can be compared to matryoshka dolls nested one inside the other. + +In the new class, we need a constructor that fills in the fields of the object in the same way as it was done in the base class. + +``` +class Rectangle : public Shape +{ +public: +   Rectangle(int px, int py, color back) : +      Shape(px, py, back) +   { +      Print(__FUNCSIG__, " ", &this); +   } +}; + +``` + +In this case, the initialization list has become a single call to the Shape constructor. You cannot directly set base class variables in an initialization list, because the base constructor is responsible for initializing them. However, if necessary, we could change the protected fields of the base class from the body of the constructor Rectangle (the statements in the function body are executed after the base constructor has completed its call in the initialization list). + +The rectangle has two dimensions, so let's add them as protected fields dx and dy. To set their values, you need to supplement the list of constructor parameters. + +``` +class Rectangle : public Shape +{ +protected: +   int dx, dy; // dimensions (width, height) +    +public: +   Rectangle(int px, int py, int sx, int sy, color back) : +      Shape(px, py, back), dx(sx), dy(sy) +   { +   } +}; + +``` + +It is important to note that the Rectangle objects implicitly contain the toString function inherited from Shape (however, draw is also present there, but it is still empty). Therefore, the following code is correct: + +``` +void OnStart() +{ +   Rectangle r(100, 200, 50, 75, clrBlue); +   Print(r.toString()); +}; + +``` + +This demonstrates not only calling toString but also creating a rectangle object using our new constructor. + +There is no default constructor (with no parameters) in the class Rectangle. This means that the user of the class cannot create rectangle objects in a simple way, without arguments: + +``` +   Rectangle r; // 'Rectangle' - wrong parameters count + +``` + +The compiler will show an error "Invalid number of arguments". + +Let's create another daughter class – Ellipse. For now, it will not differ from Rectangle in any way, except for the name. Later we will introduce the differences between them. + +``` +class Ellipse : public Shape +{ +protected: +   int dx, dy; // dimensions (large and small radii) +public: +   Ellipse(int px, int py, int rx, int ry, color back) : +      Shape(px, py, back), dx(rx), dy(ry) +   { +      Print(__FUNCSIG__, " ", &this); +   } +}; + +``` + +As the number of classes increases, it would be great to display the class name in the toString method. In the [Special sizeof and typename operators](/en/book/basis/expressions/operators_sizeof_typename) section, we described the typename operator. Let's try using it. + +Recall that typename expects one parameter, for which the type name is returned. For example, if we create a pair of objects s and r of classes Shape and Rectangle, respectively, we can find out their type in the following way: + +``` +void OnStart() +{ +   Shape s; +   Rectangle r(100, 200, 75, 50, clrRed); +   Print(typename(s), " ", typename(r));      // Shape Rectangle +} + +``` + +But we need to get this name inside the class somehow. For this purpose, let's add a string parameter to the parametric constructor Shape and store it in a new string field type (pay attention to the protected section and the modifier const: this field is hidden from the outside world and cannot be edited after the object has been created): + +``` +class Shape +{ +protected: +   ... +   const string type; +    +public: +   Shape(int px, int py, color back, string t) : +      coordinates(px, py), +      backgroundColor(back), +      type(t) +   { +      Print(__FUNCSIG__, " ", &this); +   } +   ... +}; + +``` + +In the constructors of derived classes, we fill in this parameter of the base constructor using typename(this): + +``` +class Rectangle : public Shape +{ +   ... +public: +   Rectangle(int px, int py, int sx, int sy, color back) : +      Shape(px, py, back, typename(this)), dx(sx), dy(sy) +   { +      Print(__FUNCSIG__, " ", &this); +   } +}; + +``` + +Now we can improve the method toString using the type field. + +``` +class Shape +{ +   ... +public: +   string toString() const +   { +      return type + " " + (string)coordinates.x + " " + (string)coordinates.y; +   } +}; + +``` + +Let's make sure that our little class hierarchy spawns objects as intended and prints test log entries when constructors and destructors are called. + +``` +void OnStart() +{ +   Shape s; +   //setting up an object by chaining calls via 'this' +   s.setColor(clrWhite).moveX(80).moveY(-50); +   Rectangle r(100, 200, 75, 50, clrBlue); +   Ellipse e(200, 300, 100, 150, clrRed); +   Print(s.toString()); +   Print(r.toString()); +   Print(e.toString()); +} + +``` + +As a result, we get approximately the following log entries (blank lines are added intentionally to separate the output from different objects): + +``` +Pair::Pair(int,int) 0 0 +Shape::Shape() 1048576 +    +Pair::Pair(int,int) 100 200 +Shape::Shape(int,int,color,string) 2097152 +Rectangle::Rectangle(int,int,int,int,color) 2097152 +    +Pair::Pair(int,int) 200 300 +Shape::Shape(int,int,color,string) 3145728 +Ellipse::Ellipse(int,int,int,int,color) 3145728 +    +Shape 80 -50 +Rectangle 100 200 +Ellipse 200 300 +    +Ellipse::~Ellipse() 3145728 +Shape::~Shape() 3145728 +Pair::~Pair() 200 300 +    +Rectangle::~Rectangle() 2097152 +Shape::~Shape() 2097152 +Pair::~Pair() 100 200 +    +Shape::~Shape() 1048576 +Pair::~Pair() 80 -50 + +``` + +The log makes it clear in what order the constructors and destructors are called. + +For each object, firstly, the object fields described in it are created (if there are any), and then the base constructor and all constructors of derived classes along the inheritance chain are called. If there are own (added) fields of some object types in a derived class, the constructors for them will be called immediately before the constructor of this derived class. When there are several object fields, they are created in the order in which they are described in the class. + +Destructors are called in exactly the reverse order. + +In the derived classes copy constructors can be defined, which we learned about in [Constructors: Default, Parametric, Copy](/en/book/oop/classes_and_interfaces/classes_ctors). For specific shape types, such as a rectangle, their syntax is similar: + +``` +class Rectangle : public Shape +{ +   ... +   Rectangle(const Rectangle &other) : +      Shape(other), dx(other.dx), dy(other.dy) +   { +   } +   ... +}; + +``` + +The scope is slightly expanding. A derived class object can be used to copy to a base class (because the derived class contains all the data for the base class). However, in this case, of course, the fields added in the derived class are ignored. + +``` +void OnStart() +{ +   Rectangle r(100, 200, 75, 50, clrBlue); +   Shape s2(r);         // ok: copy derived to base +    +   Shape s; +   Rectangle r4(s);     // error: no one of the overloads can be applied  +                        // requires explicit constructor overloading +} + +``` + +To copy in the opposite direction, you need to provide a constructor version with a reference to the derived class in the base class (which, in theory, contradicts the principles of OOP), otherwise the compilation error "no one of the overloads can be applied to the function call" will occur. + +Now we can script a couple or more shape variables to then "ask" them to draw themselves using the method draw. + +``` +void OnStart() +{ +   Rectangle r(100, 200, 50, 75, clrBlue); +   Ellispe e(100, 200, 50, 75, clrGreen); +   r.draw(); +   e.draw(); +}; + +``` + +However, such an entry means that the number of shapes, their types, and parameters are hardwired into the program, while the should be able to choose what and where to draw. Hence the need to create shapes in a dynamic way. diff --git a/skills/mql5/references/book/02-oop/0115-oop-classes-and-interfaces-classes-new-delete-pointers.md b/skills/mql5/references/book/02-oop/0115-oop-classes-and-interfaces-classes-new-delete-pointers.md new file mode 100644 index 0000000..0925835 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0115-oop-classes-and-interfaces-classes-new-delete-pointers.md @@ -0,0 +1,89 @@ +# Dynamic creation of objects: new and delete + +So far we have only tried to create automatic objects, i.e. local variables inside OnStart. An object declared in the global context (outside OnStart or some other function) would also be automatically created (when the script is loaded) and deleted (when the script is unloaded). + +In addition to these two modes, we have touched on the ability to describe a field of an object type (in our example, this is the structure Pair used for the field coordinates inside the object Shape). All such objects are also automatic: they are created for us by a compiler in a constructor of a "host" object and deleted in its destructor. + +However, it is quite often impossible to get by with only automatic objects in programs. In the case of a drawing program, we will need to create shapes at the user's request. Moreover, shapes will need to be stored in an array, and for this automatic objects would have to have a default constructor (which is not the case in our case. + +For such situations, MQL5 offers the opportunity to dynamically create and delete objects. Creation is implemented with the operator new and deletion with the operator delete. + +Operator new + +The keyword new is followed by the name of the required class and, in parentheses, a list of arguments to call any of the existing constructors. Execution of the operator new leads to the creation of an instance of the class. + +The operator new returns a value of a special type — a pointer to an object. To describe a variable of this type, add an asterisk character '*' after the class name. For example: + +``` +Rectangle *pr = new Rectangle(100, 200, 50, 75, clrBlue); + +``` + +Here the variable pr has a type of pointer to an object of the class Rectangle. Pointers will be discussed in more detail in a separate [section](/en/book/oop/classes_and_interfaces/classes_pointers). + +It is important to note that the declaration of a variable of an object pointer type itself does not allocate memory for an object and does not call its constructor. Of course, a pointer takes up space - 8 bytes, but in fact, it is an unsigned integer ulong, which the system interprets in a special way. + +You can work with a pointer in the same way as with an object, i.e., you can call available methods through the dereference operator and access fields. + +``` +Print(pr.toString()); + +``` + +A pointer variable that has not yet been assigned a dynamic object descriptor (for example, if the operator new is called not at the time of initialization of a new variable, but is moved to some later lines of the source code), contains a special null pointer, which is denoted as NULL (to distinguish it from numbers) but is actually equal to 0. + +Operator delete + +Pointers received via new should be freed at the end of an algorithm using the operator delete. For example: + +``` +delete pr; + +``` + +If this is not done, the instance allocated by the operator new will remain in memory. If more and more new objects are created in this way, and then not deleted when they are no longer needed, this will lead to unnecessary memory consumption. The remaining unreleased dynamic objects cause warnings to be printed when the program terminates. For example, if you don't delete the pointer pr, you'll get something like this in the log after the script is unloaded: + +``` +1 undeleted object left +1 object of type Rectangle left +168 bytes of leaked memory + +``` + +The terminal reports how many objects and what class were forgotten by the programmer, as well as how much memory they occupied. + +Once the operator delete is called for a pointer, the pointer is invalidated because the object no longer exists. A subsequent attempt to access its properties causes a run-time error "Invalid pointer accessed": + +``` +Critical error while running script 'shapes (EURUSD,H1)'. +Invalid pointer access. + +``` + +The MQL program is then interrupted. + +This, however, does not mean that the same pointer variable can no longer be used. It is enough to assign a pointer to another newly created instance of the object. + +MQL5 has a built-in function that allows you to check the validity of a pointer in a variable — CheckPointer: + +``` +ENUM_POINTER_TYPE CheckPointer(object *pointer); + +``` + +It takes one parameter of a pointer to a type class and returns a value from the ENUM_POINTER_TYPE enumeration: + +- POINTER_INVALID — incorrect pointer; +- POINTER_DYNAMIC — valid pointer to a dynamic object; +- POINTER_AUTOMATIC — valid pointer to an automatic object. + +Execution of the statement delete only makes sense for a pointer for which the function returned POINTER_DYNAMIC. For an automatic object, it will have no effect (such objects are deleted automatically when control returns from the block of code in which the variable is defined). + +The following macro simplifies and ensures the correct cleanup for a pointer: + +``` +#define FREE(P) if(CheckPointer(P) == POINTER_DYNAMIC) delete (P) + +``` + +The necessity to explicitly "clean up" is an inevitable price to pay for the flexibility provided by dynamic objects and pointers. diff --git a/skills/mql5/references/book/02-oop/0116-oop-classes-and-interfaces-classes-pointers.md b/skills/mql5/references/book/02-oop/0116-oop-classes-and-interfaces-classes-pointers.md new file mode 100644 index 0000000..9248132 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0116-oop-classes-and-interfaces-classes-pointers.md @@ -0,0 +1,207 @@ +# Pointers + +As we said in the [Class Definition](/en/book/oop/classes_and_interfaces/classes_definition) section, pointers in MQL5 are some descriptors (unique numbers) of objects, and not addresses in memory, as in C++. For an automatic object, we obtained a pointer by putting an ampersand in front of its name (in this context, the ampersand character is the "get address" operator). So, in the following example, the variable p points to the automatic object s. + +``` +Shape s;        // automatic object +Shape *p = &s;  // a pointer to the same object +s.draw();       // calling an object method +p.draw();       // doing the same + +``` + +In the previous sections, we learned how to get a pointer to an object as a result of creating it dynamically with new. At this time, an ampersand is not needed to get a descriptor: the value of the pointer is the descriptor. + +The MQL5 API provides the function GetPointer which performs the same action as the ampersand operator '&', i.e. returns a pointer to an object: + +``` +void *GetPointer(Class object); + +``` + +Which of the two options to use is a matter of preference. + +Pointers are often used to link objects together. Let's illustrate the idea of ​​creating subordinate objects that receive a pointer to this of its object-creator (ThisCallback.mq5). We mentioned this trick in the section on the keyword [this](/en/book/oop/classes_and_interfaces/classes_this). + +Let's try using it to implement a scheme for notifying the "creator" from time to time about the percentage of calculations performed in the subordinate object: we made its analog using the [function pointer](/en/book/basis/functions/functions_typedef). The class Manager controls calculations, and the calculations themselves (most probably, using different formulas) are performed in separate classes - in this example, one of them, the class Element is shown. + +``` +class Manager; // preliminary announcement +    +class Element +{ +   Manager *owner; // pointer +    +public: +   Element(Manager &t): owner(&t) { } +    +   void doMath() +   { +      const int N = 1000000; +      for(int i = 0; i < N; ++i) +      { +         if(i % (N / 20) == 0) +         { +            // we pass ourselves to the method of the control class +            owner.progressNotify(&this, i * 100.0f / N); +         } +         // ... massive calculations +      } +   } +    +   string getMyName() const +   { +      return typename(this); +   } +}; +    +class Manager +{ +   Element *elements[1]; // array of pointers (1 for demo) +    +public: +   Element *addElement() +   { +      // looking for an empty slot in the array +      // ... +      // passing to the constructor of the subclass +      elements[0] = new Element(this); // dynamic creation of an object +      return elements[0]; +   } +    +   void progressNotify(Element *e, const float percent) +   { +      // Manager chooses how to notify the user: +      // display, print, send to the Internet +      Print(e.getMyName(), "=", percent); +   } +}; + +``` + +A subordinate object can use the received link to notify the "boss" about the work progress. Reaching the end of the calculation sends a signal to the control object that it is possible to delete the calculator object, or let another one work. Of course, the fixed one-element array in the class Manager doesn't look very impressive, but as a demonstration, it gets the point across. The manager not only manages the distribution of computing tasks, but also provides an abstract layer for notifying the user: instead of outputting to a log, it can write messages to a separate file, display them on the screen, or send them to the Internet. + +By the way, pay attention to the preliminary declaration of the class Manager before the class definition Element. It is needed to describe in the class Element a pointer to the class Manager, which is defined below in the code. If the forward declaration is omitted, we get the error "'Manager' - unexpected token, probably type is missing?". + +The need for forward declaration arises when two classes refer to each other through their members: in this case, in whatever order we arrange the classes, it is impossible to fully define either of them. A forward declaration allows you to reserve a type name without a full definition. + +A fundamental property of pointers is that a pointer to a base class can be used to point to an object of any derived class. This is one of the manifestations of [polymorphism](/en/book/oop/classes_and_interfaces/classes_polymorphism). This behavior is possible because derived objects contain built-in "sub-objects" of parent classes like nesting dolls matryoshkas. + +In particular, for our task with shapes, it is easy to describe a dynamic array of pointers Shape and add objects of different types to it at the request of the user. + +The number of classes will be expanded to five (Shapes2.mq5). In addition to Rectangle and Ellipse, let's add Triangle, and also make a class derived from Rectangle for a square (Square), and a class derived from Ellipse for a circle (Circle). Obviously, a square is a rectangle with equal sides, and a circle is an ellipse with the equal large and small radii. + +To pass a string class name along the inheritance chain, let's add in the protected sections of the classes Rectangle and Ellipse special constructors with an additional string parameter t: + +``` +class Rectangle : public Shape +{ +protected: +   Rectangle(int px, int py, int sx, int sy, color back, string t) : +      Shape(px, py, back, t), dx(sx), dy(sy) +   { +   } +   ... +}; + +``` + +Then, when creating a square, we set not only equal sizes of the sides but also pass typename(this) from the class Square: + +``` +class Square : public Rectangle +{ +public: +   Square(int px, int py, int sx, color back) : +      Rectangle(px, py, sx, sx, back, typename(this)) +   { +   } +}; + +``` + +In addition, we will move constructors in the class Shape to the protected section: this will prohibit the creation of the object Shape by itself - it can only act as a base for their descendant classes. + +Let's assign the function addRandomShape to generate shapes, which returns a pointer to a newly created object. For demonstration purposes, it will now implement a random generation of shapes: their types, positions, sizes and colors. + +Supported shape types are summarized in the SHAPES enumeration: they correspond to five implemented classes. + +Random numbers in a given range are returned by the function random (it uses the built-in function [rand](/en/book/common/maths/maths_rand), which returns a random integer in the range from 0 to 32767 each time it is called. The centers of the shapes are generated in the range from 0 to 500 pixels, the sizes of the shapes are in the range of up to 200. The color is formed from three RGB components (see [Color](/en/book/basis/builtin_types/colors) section), each ranging from 0 to 255. + +``` +int random(int range) +{ +   return (int)(rand() / 32767.0 * range); +} +    +Shape *addRandomShape() +{ +   enum SHAPES +   { +      RECTANGLE, +      ELLIPSE, +      TRIANGLE, +      SQUARE, +      CIRCLE, +      NUMBER_OF_SHAPES +   }; +    +   SHAPES type = (SHAPES)random(NUMBER_OF_SHAPES); +   int cx = random(500), cy = random(500), dx = random(200), dy = random(200); +   color clr = (color)((random(256) << 16) | (random(256) << 8) | random(256)); +   switch(type) +   { +      case RECTANGLE: +         return new Rectangle(cx, cy, dx, dy, clr); +      case ELLIPSE: +         return new Ellipse(cx, cy, dx, dy, clr); +      case TRIANGLE: +         return new Triangle(cx, cy, dx, clr); +      case SQUARE: +         return new Square(cx, cy, dx, clr); +      case CIRCLE: +         return new Circle(cx, cy, dx, clr); +   } +   return NULL; +} +    +void OnStart() +{ +   Shape *shapes[]; +    +   // simulate the creation of arbitrary shapes by the user +   ArrayResize(shapes, 10); +   for(int i = 0; i < 10; ++i) +   { +      shapes[i] = addRandomShape(); +   } +    +   // processing shapes: for now, just output to the log  +   for(int i = 0; i < 10; ++i) +   { +      Print(i, ": ", shapes[i].toString()); +      delete shapes[i]; +   } +} + +``` + +We generate 10 shapes and output them to the log (the result may differ due to the randomness of the choice of types and properties). Don't forget to delete the objects with delete because they were created dynamically (here this is done in the same loop because the shapes are not used further; in a real program, the array of shapes will most likely be stored somehow to a file for later loading and continuing to work with an image). + +``` +0: Ellipse 241 38 +1: Rectangle 10 420 +2: Circle 186 38 +3: Triangle 27 225 +4: Circle 271 193 +5: Circle 293 57 +6: Rectangle 71 424 +7: Square 477 46 +8: Square 366 27 +9: Ellipse 489 105 + +``` + +The shapes are successfully created and inform about their properties. + +We are now ready to access the API of our classes, i.e. the draw method. diff --git a/skills/mql5/references/book/02-oop/0117-oop-classes-and-interfaces-classes-virtual-override.md b/skills/mql5/references/book/02-oop/0117-oop-classes-and-interfaces-classes-virtual-override.md new file mode 100644 index 0000000..e6d5f86 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0117-oop-classes-and-interfaces-classes-virtual-override.md @@ -0,0 +1,373 @@ +# Virtual methods (virtual and override) + +Classes are intended to describe external programming interfaces and provide their internal implementation. Since the functionality of our test program is to draw various shapes, we have described several variables in the class Shape and its descendants for future implementation, and also reserved the method draw for the interface. + +In the base class Shape, it shouldn't and can't do anything because Shape is not a concrete shape: we'll convert Shape to an abstract class later (we will talk more about [abstract classes and interfaces](/en/book/oop/classes_and_interfaces/classes_abstract_interfaces) later). + +Let's redefine the draw method in the Rectangle, Ellipse and other derived classes (Shapes3.mq5). This involves copying the method and modifying its content accordingly. Although many refer to this process as "overriding", we will distinguish between the two terms, reserving "overriding" exclusively for virtual methods, which will be discussed later. + +Strictly speaking, redefining a method only requires the method name to match. However, to ensure consistent usage throughout the code, it is essential to maintain the same parameter list and return type. + +``` +class Rectangle : public Shape +{ +   ... +   void draw() +   { +      Print("Drawing rectangle"); +   } +}; + +``` + +Since we don't know how to draw on the screen yet, we'll just output the message to the log. + +It is important to note that by providing a new implementation of the method in the derived class, we thereby get 2 versions of the method: one refers to the built-in base object (inner Shape), and the other to the derived one (outer Rectangle). + +The first will be called for a variable of type Shape, and the second one for a variable of type Rectangle. + +In a longer inheritance chain, a method can be redefined and propagated even more times. + +You can change an access type of a new method, for example, make it public if it was protected, or vice versa. But in this case, we left the draw method in the public section. + +If necessary, the programmer can call the implementation of the method of any of the progenitor classes: for this, a special [context resolution operator](/en/book/oop/classes_and_interfaces/classes_namespace_context) is used – two colons '::'. In particular, we could call the draw implementation from the class Rectangle from the method draw of the class Square: for this, we specify the name of the desired class, '::' and the method name, for example, Rectangle::draw(). Calling draw without specifying the context implies a method of the current class, and therefore if you do it from the method draw itself, you will get an infinite [recursion](/en/book/basis/functions/functions_recursive), and ultimately, a stack overflow and program crash. + +``` +class Square : public Rectangle +{ +public: +   ... +   void draw() +   { +      Rectangle::draw(); +      Print("Drawing square"); +   } +}; + +``` + +Then calling draw on the object Square would log two lines: + +``` +   Square s(100, 200, 50, clrGreen); +   s.draw(); // Drawing rectangle +             // Drawing square + +``` + +Binding a method to a class in which it is declared provides the static dispatch (or static binding): the compiler decides which method to call at the compilation stage and "hardwires" the found match into binary code. + +During the decision process, the compiler looks for the method to be called in the object of the class for which the dereference ('.') is performed. If the method is present, it is called, and if not, the compiler checks the parent class for the presence of the method, and so on, through the inheritance chain until the method is found. If the method is not found in any of the classes in the chain, an "undeclared identifier" compilation error will occur. + +In particular, the following code calls the setColor method on the object Rectangle: + +``` +   Rectangle r(100, 200, 75, 50, clrBlue); +   r.setColor(clrWhite); + +``` + +However, this method is defined only in the base class Shape and is built in once in all descendant classes, and therefore it will be executed here. + +Let's try to start drawing arbitrary shapes from an array in the function OnStart (recall that we have duplicated and modified the method draw in all descendant classes). + +``` +   for(int i = 0; i < 10; ++i) +   { +      shapes[i].draw(); +   } + +``` + +Oddly enough, nothing is output to the log. This happens because the program calls the method draw of the class Shape. + +There is a major drawback of static dispatch here: when we use a pointer to a base class to store an object of a derived class, the compiler chooses a method based on the type of the pointer, not the object. The fact is that at the compilation stage, it is not yet known what class object it will point to during program execution. + +Thus, there is a need for a more flexible approach: a dynamic dispatch (or binding), which would defer the choice of a method (from among all the overridden versions of the method in the descendant chain) to runtime. The choice must be made based on analysis of the actual class of the object at the pointer. It is dynamic dispatching that provides the principle of [polymorphism](/en/book/oop/classes_and_interfaces/classes_polymorphism). + +This approach is implemented in MQL5 using virtual methods. In the description of such a method, the keyword virtual must be added at the beginning of the header. + +Let's declare the method draw in the class Shape (Shapes4.mq5) as virtual. This will automatically make all versions of it in derived classes virtual as well. + +``` +class Shape +{ +   ... +   virtual void draw() +   { +   } +}; + +``` + +Once a method is virtualized, modifying it in derived classes is called overriding rather than redefinition. Overriding requires the name, parameter types, and return value of the method to match (taking into account the presence/absence of const modifiers). + +Note that overriding virtual functions is different from [function overloading](/en/book/basis/functions/functions_overloading). Overloading uses the same function name, but with different parameters (in particular, we saw the possibility of overloading a constructor in the example of structures, see [Constructors and Destructors](/en/book/oop/structs_and_unions/structs_ctor_dtor)), and overriding requires full matching of function signatures. + +  + +Overridden functions must be defined in different classes that are related by inheritance relationships. Overloaded functions must be in the same class – otherwise, it will not be an overload but, most likely, a redefinition (and it will work differently, see further analysis of the example OverrideVsOverload.mq5). + +If you run a new script, the expected lines will appear in the log, signaling calls to specific versions of the draw method in each of the classes. + +``` +Drawing square +Drawing circle +Drawing triangle +Drawing ellipse +Drawing triangle +Drawing rectangle +Drawing square +Drawing triangle +Drawing square +Drawing triangle + +``` + +In derived classes where a virtual method is overridden, it is recommended to add the keyword override to its header (although this is not required). + +``` +class Rectangle : public Shape +{ +   ... +   void draw() override +   { +      Print("Drawing rectangle"); +   } +}; + +``` + +This allows the compiler to know that we are overriding the method on purpose. If in the future the API of the base class suddenly changes and the overridden method is no longer virtual (or simply removed), the compiler will generate an error message: "method is declared with 'override' specifier, but does not override any base class method". Keep in mind that even adding or removing the modifier const from a method changes its signature, and overriding may be broken due to this. + +The keyword virtual before an overridden method is also allowed but not required. + +For dynamic dispatching to work, the compiler generates a table of virtual functions for each class. An implicit field is added to each object with a link to the given table of its class. The table is populated by the compiler based on information about all virtual methods and their overridden versions along the inheritance chain of a particular class. + +A call to a virtual method is encoded in the binary image of the program in a special way: first, the table is looked up in search of a version for a class of a particular object (located at the pointer), and then a transition is made to the appropriate function. + +As a result, dynamic dispatch is slower than static dispatch. + +In MQL5, classes always contain a table of virtual functions, regardless of the presence of virtual methods. + +If a virtual method returns a pointer to a class, then when it is overridden, it is possible to change (make it more specific, highly specialized) the object type of the return value. In other words, the type of the pointer can be not only the same as in the initial declaration of the virtual method but also any of its successors. Such types are called "covariant" or interchangeable. + +For example, if we made the method setColor virtual in the class Shape: + +``` +class Shape +{ +   ... +   virtual Shape *setColor(const color c) +   { +      backgroundColor = c; +      return &this; +   } +   ... +}; + +``` + +we could override it in the class Rectangle like this (only as a demonstration of the technology): + +``` +class Rectangle : public Shape +{ +   ... +   virtual Rectangle *setColor(const color c) override +   { +      // call original method +      // (by pre-lightening the color, +      // no matter what for) +      Rectangle::setColor(c | 0x808080); +      return &this; +   } +}; + +``` + +Note that the return type is a pointer to Rectangle instead of Shape. + +It makes sense to use a similar trick if the overridden version of the method changes something in that part of the object that does not belong to the base class, so that the object, in fact, no longer corresponds to the allowed state (invariant) of the base class. + +Our example with drawing shapes is almost ready. It remains to fill the virtual methods draw with real content. We will do this in the chapter [Graphics](/en/book/applications/objects/objects_color_style) (see example ObjectShapesDraw.mq5), but we will improve it after studying [graphic resources](/en/book/advanced/resources/resources_resourcesave). + +Taking into account the inheritance concept, the procedure by which the compiler chooses the appropriate method looks a bit confusing. Based on the method name and the specific list of arguments (their types) in the call instruction, a list of all available candidate methods is compiled. + +  + +For non-virtual methods, at the beginning only methods of the current class are analyzed. If none of them matches, the compiler will continue searching the base class (and then more distant ancestors until it finds a match). If among the methods of the current class, there is a suitable one (even if the implicit conversion of argument types is necessary), it will be picked. If the base class had a method with more appropriate argument types (no conversion or fewer conversions), the compiler still won't get to it. In other words, non-virtual methods are analyzed starting from the class of the current object towards the ancestors to the first "working" match. + +  + +For virtual methods, the compiler first finds the required method by name in the pointer class and then selects the implementation in the table of virtual functions for the most instantiated class (furthest descendant) in which this method is overridden in the chain between the pointer type and the object type. In this case, implicit argument conversion can also be used if there is no exact match between the types of arguments. + +Let's consider the following example (OverrideVsOverload.mq5). There are 4 classes that are chained: Base, Derived, Concrete and Special. All of them contain methods with type arguments int and float. In the function OnStart, the integer i and the real f variables are used as arguments for all method calls. + +``` +class Base +{ +public: +   void nonvirtual(float v) +   { +      Print(__FUNCSIG__, " ", v); +   } +   virtual void process(float v) +   { +      Print(__FUNCSIG__, " ", v); +   } +}; +  +class Derived : public Base +{ +public: +   void nonvirtual(int v) +   { +      Print(__FUNCSIG__, " ", v); +   } +   virtual void process(int v) // override +   // error: 'Derived::process' method is declared with 'override' specifier, +   // but does not override any base class method +   { +      Print(__FUNCSIG__, " ", v); +   } +}; +  +class Concrete : public Derived +{ +}; +  +class Special : public Concrete +{ +public: +   virtual void process(int v) override +   { +      Print(__FUNCSIG__, " ", v); +   } +   virtual void process(float v) override +   { +      Print(__FUNCSIG__, " ", v); +   } +}; + +``` + +First, we create an object of class Concrete and a pointer to it Base *ptr. Then we call non-virtual and virtual methods for them. In the second part, the methods of the object Special are called through the class pointers Base and Derived. + +``` +void OnStart() +{ +   float f = 2.0; +   int i = 1; +  +   Concrete c; +   Base *ptr = &c; +    +   // Static link tests +  +   ptr.nonvirtual(i); // Base::nonvirtual(float), conversion int -> float +   c.nonvirtual(i);   // Derived::nonvirtual(int) +  +   // warning: deprecated behavior, hidden method calling +   c.nonvirtual(f);   // Base::nonvirtual(float), because +                      // method selection ended in Base, +                      // Derived::nonvirtual(int) does not suit to f +  +   // Dynamic link tests +  +   // attention: there is no method Base::process(int), also +   // there are no process(float) overrides in classes up to and including Concrete +   ptr.process(i);    // Base::process(float), conversion int -> float +   c.process(i);      // Derived::process(int), because +                      // there is no override in Concrete, +                      // and the override in Special does not count +  +   Special s; +   ptr = &s; +   // attention: there is no method Base::process(int) in ptr +   ptr.process(i);    // Special::process(float), conversion int -> float +   ptr.process(f);    // Special::process(float) +  +   Derived *d = &s; +   d.process(i);      // Special::process(int) +  +   // warning: deprecated behavior, hidden method calling +   d.process(f);      // Special::process(float) +} + +``` + +The log output is shown below. + +``` +void Base::nonvirtual(float) 1.0 +void Derived::nonvirtual(int) 1 +void Base::nonvirtual(float) 2.0 +void Base::process(float) 1.0 +void Derived::process(int) 1 +void Special::process(float) 1.0 +void Special::process(float) 2.0 +void Special::process(int) 1 +void Special::process(float) 2.0 + +``` + +The ptr.nonvirtual(i) call is made using static binding, and the integer i is preliminarily cast to the parameter type, float. + +The call c.nonvirtual(i) is also static, and since there is no void nonvirtual(int) method in the class Concrete, the compiler finds such a method in the parent class Derived. + +Calling the function of the same name on the same object with a value of type float leads the compiler to the method Base::nonvirtual(float) because Derived::nonvirtual(int) is not suitable (the conversion would lead to a loss of precision). Along the way, the compiler issues a "deprecated behavior, hidden method calling" warning. + +Overloaded methods may look like overridden (have the same name but different parameters) but they are different because they are located in different classes. When a method in a derived class overrides a method in a parent class, it replaces the behavior of the parent class method which can sometimes cause unexpected effects. The programmer might expect the compiler to choose another suitable method (as in overloading), but instead the subclass is invoked. + +To avoid potential warnings, if the implementation of the parent class is necessary, it should be written as exactly the same function in the derived class, and the base class should be called from it. + +``` +class Derived : public Base +{ +public: +   ... +   // this override will suppress the warning +   // "deprecated behavior, hidden method calling" +   void nonvirtual(float v) +   { +      Base::nonvirtual(v); +      Print(__FUNCSIG__, " ", v); +   } +... + +``` + +Let's go back to tests in OnStart. + +Calling ptr.process(i) demonstrates the confusion between overloading and overriding described above. The Base class has a process(float) virtual method, and the class Derived adds a new virtual method process(int), which is not overriding in this case because parameter types are different. The compiler selects a method by name in the base class and checks the virtual function table for overrides in the inheritance chain up to the Concrete class (inclusive, this is the object class by pointer). Since no overrides were found, the compiler took Base::process(float) and applied the type conversion of the argument to the parameter (int to float). + +If we followed the rule of always writing the word override where redefining is implied and added it to Derived, we would get an error: + +``` +class Derived : public Base +{ +   ... +   virtual void process(int v) override // error! +   { +      Print(__FUNCSIG__, " ", v); +   } +}; + +``` + +The compiler would report "'Derived::process' method is declared with 'override' specifier, but does not override any base class method". This would serve as a hint to fixing the problem. + +Calling process(i) on the Concrete object is done with Derived::process(int). Although we have an even further redefinition in the class Special, it is irrelevant because it's done in the inheritance chain after the Concrete class. + +When the pointer ptr is later assigned to the Special object, calls to process(i) and process(f) are resolved by the compiler as Special::process(float) because Special overrides Base::process(float). The choice of the float parameter occurs for the same reason as described earlier: the method Base::process(float) is overridden by Special. + +If we apply the pointer d of type Derived, then we finally get the expected call Special::process(int) for the string d.process(i). The point is that process(int) is defined in Derived, and falls into the scope of the compiler's search. + +Note that the Special class not only overrides the inherited virtual methods but also overloads two methods in the class itself. + +Do not call a virtual function from a constructor or destructor! While technically possible, the virtual behavior in the constructor and destructor is completely lost and you might get unexpected results. Not only explicit but also indirect calls should be avoided (for example, when a simple method is called from a constructor, which in turn calls a virtual one). + +  + +Let's analyze the situation in more detail using the example of a constructor. The fact is that at the time of the constructor's work, the object is not yet fully assembled along the entire inheritance chain, but only up to the current class. All derived part have yet to be "finished" around the existing core. Therefore, all later virtual method overrides (if any) are not yet available at this point. As a result, the current version of the method will be called from the constructor. diff --git a/skills/mql5/references/book/02-oop/0118-oop-classes-and-interfaces-classes-static.md b/skills/mql5/references/book/02-oop/0118-oop-classes-and-interfaces-classes-static.md new file mode 100644 index 0000000..d76ea4f --- /dev/null +++ b/skills/mql5/references/book/02-oop/0118-oop-classes-and-interfaces-classes-static.md @@ -0,0 +1,88 @@ +# Static members + +So far, we have considered the fields and methods of a class that describe the state and behavior of objects of a given class. However, in programs, it may be necessary to store certain attributes or perform operations on the entire class, rather than on its objects. Such class properties are called static and are described using the static keyword added before the type. They are also supported in structures and unions. + +For example, we can count the number of shapes created by the user in a drawing program. To do this, in the class Shape, we will describe the static variable count(Shapes5.mq5). + +``` +class Shape +{ +private: +   static int count; +    +protected: +   ... +   Shape(int px, int py, color back, string t) : +      coordinates(px, py), +      backgroundColor(back), +      type(t) +   { +      ++count; +   } +    +public: +   ... +   static int getCount() +   { +      return count; +   } +}; + +``` + +It is defined in the private section and therefore not accessible from the outside. + +To read the current counter value, a public static method getCount() is provided. In theory, since static members are defined in the context of a class, they receive visibility restrictions according to the modifier of the section in which they are located. + +We will increase the counter by 1 in the parametric constructor Shape, and remove the default constructor. Thus, each instance of a shape of any derived type will be taken into account. + +Note that a static variable must be explicitly defined (and optionally initialized) outside the class block: + +``` +static int Shape::count = 0; + +``` + +Static class variables are similar to global variables and static variables inside functions (see section [Static variables](/en/book/basis/variables/static_variables)) in the sense that they are created when the program starts and are deleted before it is unloaded. Therefore, unlike object variables, they must exist from the beginning as a single instance. + +In this case, zero-initialization can be omitted because, as we know, global and static variables are set to zero by default. Arrays can also be static. + +In the definition of a static variable, we see the use of the special context selection operator ['::'](/en/book/oop/classes_and_interfaces/classes_namespace_context). With it, a fully qualified variable name is formed. To the left of '::' is the name of the class to which the variable belongs, and to the right is its identifier. Obviously, the fully qualified name is necessary, because within different classes static variables with the same identifier can be declared, and a way to uniquely refer to each of them is needed. + +The same '::' operator is used to access not only public static class variables but also methods. In particular, in order to call the method getCount in the OnStart function, we use the syntax Shape::getCount(): + +``` +void OnStart() +{ +   for(int i = 0; i < 10; ++i) +   { +      Shape *shape = addRandomShape(); +      shape.draw(); +      delete shape; +   } +    +   Print(Shape::getCount()); // 10 +} + +``` + +Since the specified number of shapes (10) is now being generated, we can verify that the counter is working correctly. + +If you have a class object, you can refer to a static method or property through the usual dereference (for example, shape.getCount()), but such a notation can be misleading (because it hides the fact that the object is actually not accessed). + +Note that the creation of derived classes does not affect static variables and methods in any way: they are always assigned to the class in which they were defined. Our counter is the same for all classes of shapes derived from Shape. + +You can't use this inside static methods because they are executed without being tied to a specific object. Also, from a static method, you cannot directly, without dereferencing any object type variable, call a regular class method or access its field. For example, if you call draw from getCount, you get an "access to non-static member or function" error: + +``` +   static int getCount() +   { +      draw(); // error: 'draw' - access to non-static member or function +      return count; +   } + +``` + +For the same reason, static methods cannot be virtual. + +Is it possible, using static variables, to calculate not the total number of shapes, but their statistics by type? Yes, it is possible. This task is left for independent study. Those interested can find one of the implementation examples in the script Shapes5stats.mq5. diff --git a/skills/mql5/references/book/02-oop/0119-oop-classes-and-interfaces-classes-namespace-context.md b/skills/mql5/references/book/02-oop/0119-oop-classes-and-interfaces-classes-namespace-context.md new file mode 100644 index 0000000..1e3b6bd --- /dev/null +++ b/skills/mql5/references/book/02-oop/0119-oop-classes-and-interfaces-classes-namespace-context.md @@ -0,0 +1,171 @@ +# Nested types, namespaces, and the context operator '::' + +Classes, structures, and unions can be described not only in the global context but also within another class or structure. And even more: the definition can be done inside the function. This allows you to describe all the entities necessary for the operation of any class or structure within the appropriate context and thereby avoid potential name conflicts. + +In particular, in the drawing program, the structure for storing coordinates Pair has been defined globally so far. As the program grows, it is quite possible that another entity called Pair will be needed (especially given the rather generic name). Therefore, it is desirable to move the description of the structure inside the class Shape (Shapes6.mq5). + +``` +class Shape +{ +public: +   struct Pair +   { +      int x, y; +      Pair(int a, int b): x(a), y(b) { } +   }; +   ... +}; + +``` + +The nested descriptions have access permissions in accordance with the specified section modifiers. In this case, we have made the name Pair publicly available. Inside the class Shape, the handling of the Pair structure type does not change in any way due to the transfer. However, in external code, you must specify a fully qualified name that includes the name of the external class (context), the context selection operator '::' and the internal entity identifier itself. For example, to describe a variable with a pair of coordinates, you would write: + +``` +Shape::Pair coordinates(0, 0); + +``` + +The level of nesting when describing entities is not limited, so a fully qualified name can contain identifiers of multiple levels (contexts) separated by '::'. For example, we could wrap all drawing classes inside the outer class Drawing, in the public section. + +``` +class Drawing +{ +public: +   class Shape +   { +   public: +      struct Pair +      { +         ... +      }; +   }; +   class Rectangle : public Shape +   { +      ... +   }; +   ... +}; + +``` + +Then fully qualified type names (e.g. for use in OnStart or other external functions) would be lengthened: + +``` +Drawing::Shape::Rect coordinates(0, 0); +Drawing::Rectangle rect(200, 100, 70, 50, clrBlue); + +``` + +On the one hand, this is inconvenient, but on the other hand, it is sometimes a necessity in large projects with a large number of classes. In our small project, this approach is used only to demonstrate the technical feasibility. + +To combine logically related classes and structures into named groups, MQL5 provides an easier way than including them in an "empty" wrapper class. + +A namespace is declared using the keyword namespace followed by the name and a block of curly braces that includes all the necessary definitions. Here's what the same paint program looks like using namespace: + +``` +namespace Drawing +{ +   class Shape +   { +   public: +      struct Pair +      { +         ... +      }; +   }; +   class Rectangle : public Shape +   { +      ... +   }; +   ... +} + +``` + +There are two main differences: the internal contents of the space are always available publicly (access modifiers are not applicable in it) and there is no semicolon after the closing curly brace. + +Let's add the method move to the class Shape, which takes the structure Pair as a parameter: + +``` +class Shape +{ +public: +   ... +   Shape *move(const Pair &pair) +   { +      coordinates.x += pair.x; +      coordinates.y += pair.y; +      return &this; +   } +}; + +``` + +Then, in the function OnStart, you can organize the shift of all shapes by a given value by calling this function: + +``` +void OnStart() +{ +   //draw a random set of shapes +   for(int i = 0; i < 10; ++i) +   { +      Drawing::Shape *shape = addRandomShape(); +      // move all shapes +      shape.move(Drawing::Shape::Pair(100, 100)); +      shape.draw(); +      delete shape; +   } +} + +``` + +Note that the types Shape and Pair have to be described with full names: Drawing::Shape and Drawing::Shape::Pair respectively. + +There may be several blocks with the same space name: all their contents will fall into one logically unified context with the specified name. + +Identifiers defined in the global context, in particular all built-in functions of the MQL5 API, are also available through the context selection operator not preceded by any notation. For example, here's what a call to the function Print might look like: + +``` +::Print("Done!"); + +``` + +When the call is made from any function defined in the global context, there is no need for such an entry. + +Necessity can manifest itself inside any class or structure if an element of the same name (function, variable or constant) is defined in them. For example, let's add the method Print to the class Shape: + +``` +   static void Print(string x) +   { +      // empty +      // (likely will output it to a separate log file later) +   } + +``` + +Since the test implementations of the draw method in derived classes call Print, they are now redirected to this Print method: from several identical identifiers, the compiler chooses the one that is defined in a closer context. In this case, the definition in the base class is closer to the shapes than the global context. As a result, logging output from shape classes will be suppressed. + +However, calling Print from the function OnStart still works (because it is outside the context of the class Shape). + +``` +void OnStart() +{ +   ... +   Print("Done!"); +} + +``` + +To "fix" debug printing in classes, you need to precede all Print calls with a global context selection operator: + +``` +class Rectangle : public Shape +{ +   ... +   void draw() override +   { +      ::Print("Drawing rectangle"); // reprint via global Print(...) +   } +}; + +``` diff --git a/skills/mql5/references/book/02-oop/0120-oop-classes-and-interfaces-classes-declaration-definition.md b/skills/mql5/references/book/02-oop/0120-oop-classes-and-interfaces-classes-declaration-definition.md new file mode 100644 index 0000000..af8d2a6 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0120-oop-classes-and-interfaces-classes-declaration-definition.md @@ -0,0 +1,100 @@ +# Splitting class declaration and definition + +In large software projects, it is convenient to separate classes into a brief description (declaration) and a definition, which includes the main implementation details. In some cases, such a separation becomes necessary if the classes somehow refer to each other, that is, none can be fully defined without prior declarations. + +We saw an example of a forward declaration in the section [Indicators](/en/book/oop/classes_and_interfaces/classes_pointers) (see file ThisCallback.mq5), where classes Manager and Element contain reciprocal pointers. There, the class was pre-declared in a short form: in the form of a header with the keyword class and a name: + +``` +class Manager; + +``` + +However, this is the shortest declaration possible. It registers only the name and makes it possible to postpone the description of the programming interface until some time, but this description must be encountered somewhere later in the code. + +More often, the declaration includes a complete description of the interface: it specifies all the variables and method headers of the class but without their bodies (code blocks). + +Method definitions are written separately: with headers that use fully qualified names that include the name of the class (or multiple classes and namespaces if the method context is highly nested). The names of all classes and the name of the method are concatenated using the context selection operator '::'. + +``` +type class_name [:: nested_class_name...] :: method_name([parameters...]) +{ +} + +``` + +In theory, you can define part of the methods directly in the class description block (usually they do this with small functions), and some can be taken out separately (as a rule, large functions). But a method must have only one definition (that is, you cannot define a method in a class block, and then again separately) and one declaration (a definition in a class block is also a declaration). + +The list of parameters, return type and const modifiers (if any) must match exactly in the method declaration and definition. + +Let's see how we can separate the description and definition of classes from the script ThisCallback.mq5 (an example from the section [Pointers](/en/book/oop/classes_and_interfaces/classes_pointers)): let's create its analog with the name ThisCallback2.mq5. + +The predeclaration Manager will still come at the beginning. Further, both classes Element and Manager are declared without implementation: instead of a block of code with a method body, there is a semicolon. + +``` +class Manager; // preliminary announcement +   +class Element +{ +   Manager *owner; // pointer +public: +   Element(Manager &t); +   void doMath(); +   string getMyName() const; +}; +   +class Manager +{ +   Element *elements[1]; // array of pointers (replace with dynamic) +public: +   ~Manager(); +   Element *addElement(); +   void progressNotify(Element *e, const float percent); +}; + +``` + +The second part of the source code contains implementations of all methods (the implementations themselves are unchanged). + +``` +Element::Element(Manager &t) : owner(&t) +{ +} +  +void Element::doMath() +{ +   ... +} +  +string Element::getMyName() const +{ +   return typename(this); +} +  +Manager::~Manager() +{ +   ... +} +  +Element *Manager::addElement() +{ +   ... +} +  +void Manager::progressNotify(Element *e, const float percent) +{ +   ... +} + +``` + +Structures also support separate method declarations and definitions. + +Note that the constructor initialization list (after the name and ':') is a part of the definition and therefore must precede the function body (in other words, the initialization list is not allowed in a constructor declaration where only the header is present). + +Separate writing of the declaration and definition allows the development of [libraries](/en/book/advanced/libraries), the source code of which must be closed. In this case, the declarations are placed in a separate header file with the mqh extension, while the definitions are placed in a file of the same name with the mq5 extension. The program is compiled and distributed as an ex5 file with a header file describing the external interface. + +In this case, the question may arise why part of the internal implementation, in particular the organization of data (variables), is visible in the external interface. Strictly speaking, this signals an insufficient level of abstraction in the class hierarchy. All classes that provide an external interface should not expose any implementation details. + +In other words, if we set ourselves the goal of exporting the above classes from a certain library, then we would need to separate their methods into base classes that would provide a description of the API (without data fields), and Manager and Element inherit from them. At the same time, in the methods of base classes, we cannot use any data from derived classes and, by and large, they cannot have implementations at all. How is it possible? + +To do this, there is a technology of abstract methods, abstract classes and interfaces. diff --git a/skills/mql5/references/book/02-oop/0121-oop-classes-and-interfaces-classes-abstract-interfaces.md b/skills/mql5/references/book/02-oop/0121-oop-classes-and-interfaces-classes-abstract-interfaces.md new file mode 100644 index 0000000..b077010 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0121-oop-classes-and-interfaces-classes-abstract-interfaces.md @@ -0,0 +1,100 @@ +# Abstract classes and interfaces + +To explore abstract classes and interfaces, let's go back to our end-to-end drawing program example. Its API for simplicity consists of a single virtual method draw. Until now, it has been empty, but at the same time, even such an empty implementation is a concrete implementation. However, objects of the class Shape cannot be drawn - their shape is not defined. Therefore, it makes sense to make the method draw abstract or, as it is otherwise called, purely virtual. + +To do this, the block with an empty implementation should be removed, and "= 0" should be added to the method header: + +``` +class Shape +{ +public: +   virtual void draw() = 0; +   ... + +``` + +A class that has at least one abstract method also becomes abstract, because its object cannot be created: there is no implementation. In particular, our constructor Shape was available to derived classes (thanks to the protected modifier), and their developers could, hypothetically, create an object Shape. But it was like that before, and after the declaration of the abstract method, we stopped this behavior, as it was forbidden by us, the authors of the drawing interface. The compiler will throw an error: + +``` +'Shape' -cannot instantiate abstract class +      'void Shape::draw()' is abstract + +``` + +The best approach to describe an interface is to create an abstract class for it, containing only abstract methods. In our case, the method draw should be moved to the new class Drawable, and the class Shape should be inherited from it (Shapes.mq5). + +``` +class Drawable +{ +public: +   virtual void draw() = 0; +}; +  +class Shape : public Drawable +{ +public: +   ... +   // virtual void draw() = 0; // moved to base class +   ... +}; + +``` + +Of course, interface methods must be in the section public. + +MQL5 provides another convenient way to describe interfaces by using the keyword interface. All methods in an interface are declared without implementation and are considered public and virtual. The description of the Drawable interface which is equivalent to the above class looks like this: + +``` +interface Drawable +{ +   void draw(); +}; + +``` + +In this case, nothing needs to be changed in the descendant classes if there were no fields in the abstract class (which would be a violation of the abstraction principle). + +Now it's time to expand the interface and make the trio of methods setColor, moveX, moveY also part of it. + +``` +interface Drawable +{ +   void draw(); +   Drawable *setColor(const color c); +   Drawable *moveX(const int x); +   Drawable *moveY(const int y); +}; + +``` + +Note that the methods return a Drawable object because I don't know anything about Shape. In the Shape class, we already have implementations that are suitable for overriding these methods, because Shape inherits from Drawable (Shape "are sort of" Drawable objects). + +Now third-party developers can add other families of Drawable classes to the drawing program, in particular, not only shapes, but also text, bitmaps, and also, amazingly, collections of other Drawables, which allows you to nest objects in each other and make complex compositions. It is enough to inherit from the interface and implement its methods. + +``` +class Text : public Drawable +{ +public: +   Text(const string label) +   { +      ... +   } +    +   void draw() +   { +      ... +   } +    +   Text *setColor(const color c) +   { +      ... +      return &this; +   } +   ... +}; + +``` + +If the shape classes were distributed as a binary ex5 library (without source codes), we would supply a header file for it containing only the description of the interface, and no hints about the internal data structures. + +Since virtual functions are dynamically (later) bound to an object during program execution, it is possible to get a "Pure virtual function call" fatal error: the program terminates. This happens if the programmer inadvertently "forgot" to provide an implementation. The compiler is not always able to detect such omissions at compile time. diff --git a/skills/mql5/references/book/02-oop/0122-oop-classes-and-interfaces-classes-operator-overloading.md b/skills/mql5/references/book/02-oop/0122-oop-classes-and-interfaces-classes-operator-overloading.md new file mode 100644 index 0000000..497e6d4 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0122-oop-classes-and-interfaces-classes-operator-overloading.md @@ -0,0 +1,494 @@ +# Operator overloading + +In the [Expressions](/en/book/basis/expressions) chapter, we learned about various operations defined for built-in types. For example, for variables of type double, we could evaluate the following expression: + +``` +double a = 2.0, b = 3.0, c = 5.0; +double d = a * b + c; + +``` + +It would be convenient to use a similar syntax when working with user-defined types, such as matrices: + +``` +Matrix a(3, 3), b(3, 3), c(3, 3); // creating 3x3 matrices +// ... somehow fill in a, b, c +Matrix d = a * b + c; + +``` + +MQL5 provides such an opportunity due to operator overloading. + +This technique is organized by describing methods with a name beginning with the keyword operator and then containing a symbol (or sequence of symbols) of one of the supported operations. In a generalized form, this can be represented as follows: + +``` +result_type operator@ ( [type parameter_name] ); + +``` + +Here @ - operation's symbol(s). + +The complete list of MQL5 operations has been provided in the section [Operation Priorities](/en/book/basis/expressions/operators_precedence), however, not all of them are allowed for overloading. + +Forbidden for overloading: + +- colons '::', context permission; +- parentheses '()', "function call" or "grouping"; +- dot '.', "dereference"; +- ampersand '&', "taking address", unary operator (however, the ampersand is available as binary operator "bitwise AND"); +- conditional ternary '?:'; +- comma ','. + +All other operators are available for overloading. Overloading operator priorities cannot be changed, they remain equal to the standard precedence, so grouping with parentheses should be used if necessary. + +You cannot create an overload for some new character that is not included in the standard list. + +All operators are overloaded taking into account their unarity and binarity, that is, the number of required operands is preserved. Like any class method, operator overloading can return a value of some type. In this case, the type itself should be chosen based on the planned logic of using the result of the function in expressions (see further along). + +Operator overloading methods have the following form (instead of the '@' symbol, the symbol(s) of the required operator is substituted): + +| Name | Method header | Using + in an expression | Function + is equivalent to | +| --- | --- | --- | --- | +| unary prefix | type operator@() | @object | object.operator@() | +| unary postfix | type operator@(int) | object@ | object.operator@(0) | +| binary | type operator@(type parameter_name) | object@argument | object.operator@(argument) | +| index | type operator[](type index_name) | object[argument] | object.operator[](argument) | + +Unary operators do not take parameters. Of the unary operators, only the increment '++' and decrement '--' operators support the postfix form in addition to the prefix form, all other unary operators only support the prefix form. Specifying an anonymous parameter of type int is used to denote the postfix form (to distinguish it from the prefix form), but the parameter itself is ignored. + +Binary operators must take one parameter. For the same operator, several overloaded variants are possible with a parameter of a different type, including the same type as the class of the current object. In this case, objects as parameters can only be passed by reference or by pointer (the latter is only for class objects, but not structures). + +Overloaded operators can be used both via the syntax of operations as part of expressions (which is the primary reason for overloading) and the syntax of method calls; both options are shown in the table above. The functional equivalent makes it more obvious that technically speaking, an operator is nothing more than a method call on an object, with the object to the right of the prefix operator and to the left of the symbol for all others. The binary operator method will be passed as an argument the value or expression that is to the right of the operator (this can be, in particular, another object or variable of a built-in type). + +It follows that overloaded operators do not have the commutativity property: a@b is not generally equal to b@a, because for a the @ operator may be overloaded, but b is not. Moreover, if b is a variable or value of a built-in type, then in principle you cannot overload the standard behavior for it. + +As a first example, consider the class Fibo for generating numbers from the Fibonacci series (we have already done one implementation of this task using functions, see [Function definition](/en/book/basis/functions/functions_definition)). In the class, we will provide 2 fields for storing the current and previous number of the row: current and previous, respectively. The default constructor will initialize them with the values ​​1 and 0. We will also provide a copy constructor (FiboMonad.mq5). + +``` +class Fibo +{ +   int previous; +   int current; +public: +   Fibo() : current(1), previous(0) { } +   Fibo(const Fibo &other) : current(other.current), previous(other.previous) { } +   ... +}; + +``` + +The initial state of the object: the current number is 1, and the previous one is 0. To find the next number in the series, we overload the prefix and postfix increment operators. + +``` +   Fibo *operator++() // prefix +   { +      int temp = current; +      current = current + previous; +      previous = temp; +      return &this; +   } +    +   Fibo operator++(int) // postfix +   { +      Fibo temp = this; +      ++this; +      return temp; +   } + +``` + +Please note that the prefix method does not return a pointer to the current object Fibo after the number has been modified, but the postfix method returns to a new object with the previous counter saved, which corresponds to the principles of postfix increment. + +If necessary, the programmer, of course, can overload any operation in an arbitrary way. For example, it is possible to calculate the product, output the number to the log, or do something else in the implementation of the increment. However, it is recommended to stick to the approach where operator overloading performs intuitive actions. + +We implement decrement operations in a similar way: they will return the previous number of the series. + +``` +   Fibo *operator--() // prefix +   { +      int diff = current - previous; +      current = previous; +      previous = diff; +      return &this; +   } +    +   Fibo operator--(int) // postfix +   { +      Fibo temp = this; +      --this; +      return temp; +   } + +``` + +To get a number from a series by a given number, we will overload the index access operation. + +``` +   Fibo *operator[](int index) +   { +      current = 1; +      previous = 0; +      for(int i = 0; i < index; ++i) +      { +         ++this; +      } +      return &this; +   } + +``` + +To get the current number contained in the current variable, let's overload the '~' operator (since it is rarely used). + +``` +   int operator~() const +   { +      return current; +   } + +``` + +Without this overload, you would still need to implement some public method to read the private field current. We will use this operator to output numbers with Print. + +You should also overload the assignment for convenience. + +``` +   Fibo *operator=(const Fibo &other) +   { +      current = other.current; +      previous = other.previous; +      return &this; +   } +    +   Fibo *operator=(const Fibo *other) +   { +      current = other.current; +      previous = other.previous; +      return &this; +   } + +``` + +Let's check, how it all works. + +``` +void OnStart() +{ +   Fibo f1, f2, f3, f4; +   for(int i = 0; i < 10; ++i, ++f1) // prefix increment +   { +      f4 = f3++; // postfix increment and assignment overloading +   } +    +   // compare all values ​​obtained by increments and by index [10] +   Print(~f1, " ", ~f2[10], " ", ~f3, " ", ~f4); // 89 89 89 55 +    +   // counting in opposite direction, down to 0 +   Fibo f0; +   Fibo f = f0[10]; // copy constructor (due to initialization) +   for(int i = 0; i < 10; ++i) +   { +      // prefix decrement +      Print(~--f); // 55, 34, 21, 13, 8, 5, 3, 2, 1, 1 +   } +} + +``` + +The results are as expected. Still, we have to consider one detail. + +``` +   Fibo f5; +   Fibo *pf5 = &f5; +    +   f5 = f4;   // call Fibo *operator=(const Fibo &other)  +   f5 = &f4;  // call Fibo *operator=(const Fibo *other) +   pf5 = &f4; // calls nothing, assigns &f4 to pf5! + +``` + +Overloading the assignment operator for a pointer only works when accessed via an object. If the access goes via a pointer, then there is a standard assignment of one pointer to another. + +The return type of an overloaded operator can be one of the built-in types, an object type (of a class or structure), or a pointer (for class objects only). + +To return an object (an instance, not a reference), the class must implement a copy constructor. This way will cause instance duplication, which can affect the efficiency of the code. If possible, you should return a pointer. + +However, when returning a pointer, you need to make sure that it is not returning a local automatic object (which will be deleted when the function exits, and the pointer will become invalid), but some already existing one - as a rule, &this is returned. + +Returning an object or a pointer to an object allows you to "send" the result of one overloaded operator to another, and thereby construct complex expressions in the same way as we are accustomed to doing with built-in types. Returning void will make it impossible to use the operator in expressions. For example, if the '=' operator is defined with type void, then the multiple assignment will stop working: + +``` +Type x, y, z = 1; // constructors and initialization of variables of a certain class +x = y = z; // assignments, compilation error  + +``` + +The assignment chain runs from right to left, and y = z will return empty. + +If objects contain fields of built-in types only (including arrays), then the assignment/copy operator '=' from objects of the same class does not need to be redefined: MQL5 provides "one-to-one" copying of all fields by default. The assignment/copy operator should not be confused with the copy constructor and initialization. + +Now let's turn to the second example: working with matrices(Matrix.mq5). + +Note, by the way, that the built-in object types [matrices and vectors](/en/book/common/matrices) have recently appeared in MQL5. Whether to use built-in types or your own (or maybe combine them) is the choice of each developer. Ready-made and fast implementation of many popular methods in built-in types is convenient and eliminates routine coding. On the other hand, custom classes allow you to adapt algorithms to your tasks. Here we provide the class Matrix as a tutorial. + +In the matrix class, we will store its elements in a one-dimensional dynamic array m. Under the sizes, select the variables rows and columns. + +``` +class Matrix +{ +protected: +   double m[]; +   int rows; +   int columns; +   void assign(const int r, const int c, const double v) +   { +      m[r * columns + c] = v; +   } +       +public: +   Matrix(const Matrix &other) : rows(other.rows), columns(other.columns) +   { +      ArrayCopy(m, other.m); +   } +    +   Matrix(const int r, const int c) : rows(r), columns(c) +   { +      ArrayResize(m, rows * columns); +      ArrayInitialize(m, 0); +   } + +``` + +The main constructor takes two parameters (matrix dimensions) and allocates memory for the array. There is also a copy constructor from the other matrix other. Here and below, built-in functions for working with arrays are massively used (in particular, ArrayCopy, ArrayResize, ArrayInitialize) — they will be considered in a separate [chapter](/en/book/common/arrays). + +We organize the filling of elements from an external array by overloading the assignment operator: + +``` +   Matrix *operator=(const double &a[]) +   { +      if(ArraySize(a) == ArraySize(m)) +      { +         ArrayCopy(m, a); +      } +      return &this; +   } + +``` + +To implement the addition of two matrices, we overload the operations '+=' and '+': + +``` +   Matrix *operator+=(const Matrix &other) +   { +      for(int i = 0; i < rows * columns; ++i) +      { +         m[i] += other.m[i]; +      } +      return &this; +   } +    +   Matrix operator+(const Matrix &other) const +   { +      Matrix temp(this); +      return temp += other; +   } + +``` + +Note that the operator '+=' returns a pointer to the current object after it has been modified, while the operator '+' returns a new instance by value (the copy constructor will be used), and the operator itself has the const modifier, so how does not change the current object. + +The operator '+' is essentially a wrapper that delegates all the work to the operator '+=', having previously created a temporary copy of the current matrix under the name temp to call it. Thus, temp is added to other by an internal call to the operator '+=' (with temp being modified) and then returned as the result of the ' +'. + +Matrix multiplication is overloaded similarly, with two operators '*=' and '*'. + +``` +   Matrix *operator*=(const Matrix &other) +   { +      // multiplication condition: this.columns == other.rows +     // the result will be a matrix of size this.rows by other.columns +      Matrix temp(rows, other.columns); +       +      for(int r = 0; r < temp.rows; ++r) +      { +         for(int c = 0; c < temp.columns; ++c) +         { +            double t = 0; +            //we add up the pairwise products of the i-th elements +           // row 'r' of the current matrix and column 'c' of the matrix other +            for(int i = 0; i < columns; ++i) +            { +               t += m[r * columns + i] * other.m[i * other.columns + c]; +            } +            temp.assign(r, c, t); +         } +      } +      // copy the result to the current object of the matrix this +      this = temp; // calling an overloaded assignment operator +      return &this; +   } +    +   Matrix operator*(const Matrix &other) const +   { +      Matrix temp(this); +      return temp *= other; +   } + +``` + +Now, we multiply the matrix by a number: + +``` +   Matrix *operator*=(const double v) +   { +      for(int i = 0; i < ArraySize(m); ++i) +      { +         m[i] *= v; +      } +      return &this; +   } +    +   Matrix operator*(const double v) const +   { +      Matrix temp(this); +      return temp *= v; +   } + +``` + +To compare two matrices, we provide the operators '==' and '!=': + +``` +   bool operator==(const Matrix &other) const +   { +      return ArrayCompare(m, other.m) == 0; +   } +    +   bool operator!=(const Matrix &other) const +   { +      return !(this == other); +   } + +``` + +For debugging purposes, we implement the output of the matrix array to the log. + +``` +   void print() const +   { +      ArrayPrint(m); +   } + +``` + +In addition to the described overloads, the class Matrix additionally has an overload of the operator []: it returns an object of the nested class MatrixRow, i.e., a row with a given number. + +``` +   MatrixRow operator[](int r) +   { +      return MatrixRow(this, r); +   } + +``` + +The class MatrixRow itself provides more "deep" access to the elements of the matrix by overloading the same operator [] (that is, for a matrix, it will be possible to naturally specify two indexes m[i][j]). + +``` +   class MatrixRow +   { +   protected: +      const Matrix *owner; +      const int row; +       +   public: +      class MatrixElement +      { +      protected: +         const MatrixRow *row; +         const int column; +          +      public: +         MatrixElement(const MatrixRow &mr, const int c) : row(&mr), column(c) { } +         MatrixElement(const MatrixElement &other) : row(other.row), column(other.column) { } +          +         double operator~() const +         { +            return row.owner.m[row.row * row.owner.columns + column]; +         } +          +         double operator=(const double v) +         { +            row.owner.m[row.row * row.owner.columns + column] = v; +            return v; +         } +      }; +    +      MatrixRow(const Matrix &m, const int r) : owner(&m), row(r) { } +      MatrixRow(const MatrixRow &other) : owner(other.owner), row(other.row) { } +       +      MatrixElement operator[](int c) +      { +         return MatrixElement(this, c); +      } +    +      double operator[](uint c) +      { +         return owner.m[row * owner.columns + c]; +      } +   }; + +``` + +The operator [] for a type parameter int returns an object of class MatrixElement, through which you can write a specific element in the array. To read an element, the operator [] is used with a type parameter uint. This seems like a trick, but this is a language limitation: overloads must differ in the parameter type. As an alternative to reading an element, the class MatrixElement provides an overload of the operator '~'. + +When working with matrices, you often need an identity matrix, so let's create a derived class for it: + +``` +class MatrixIdentity : public Matrix +{ +public: +   MatrixIdentity(const int n) : Matrix(n, n) +   { +      for(int i = 0; i < n; ++i) +      { +         m[i * rows + i] = 1; +      } +   } +}; + +``` + +Now let's try matrix expressions in action. + +``` +void OnStart() +{ +   Matrix m(2, 3), n(3, 2); // description +   MatrixIdentity p(2);     // identity matrix +    +   double ma[] = {-1,  0, -3, +                   4, -5,  6}; +   double na[] = {7,  8, +                  9,  1, +                  2,  3}; +   m = ma; // filling in data +   n = na; +    +   //we can read and write elements separately +   m[0][0] = m[0][(uint)0] + 2; // variant 1  +   m[0][1] = ~m[0][1] + 2;      // variant 2  +    +   Matrix r = m * n + p;                    // expression +   Matrix r2 = m.operator*(n).operator+(p); // equivalent +   Print(r == r2); // true +    +   m.print(); // 1.00000  2.00000 -3.00000  4.00000 -5.00000  6.00000 +   n.print(); // 7.00000 8.00000 9.00000 1.00000 2.00000 3.00000 +   r.print(); // 20.00000  1.00000 -5.00000  46.00000 +} + +``` + +Here we have created 2 matrices of 3 by 2 and 2 by 3 dimensions, respectively, then filled them with values ​​from arrays and edited the selective element using the syntax of two indexes [][]. Finally, we calculated the expression m * n + p, where all operands are matrices. The line below shows the same expression in the form of method calls. We've got the same results. + +Unlike C++, MQL5 does not support operator overloading at the global level. In MQL5, an operator can only be overloaded in the context of a class or structure, that is, using their method. Also, MQL5 does not support overloading of type casting, operators new and delete. diff --git a/skills/mql5/references/book/02-oop/0123-oop-classes-and-interfaces-classes-dynamic-cast-void.md b/skills/mql5/references/book/02-oop/0123-oop-classes-and-interfaces-classes-dynamic-cast-void.md new file mode 100644 index 0000000..bec45bf --- /dev/null +++ b/skills/mql5/references/book/02-oop/0123-oop-classes-and-interfaces-classes-dynamic-cast-void.md @@ -0,0 +1,196 @@ +# Object type casting: dynamic_cast and pointer void * + +Object types have specific casting rules which apply when source and destination variable types do not match. Rules for built-in types have already been discussed in Chapter 2.6 [Type conversion](/en/book/basis/conversion). The specifics of structure type casting of structures when copying were described in the [Structure layout and inheritance](/en/book/oop/structs_and_unions/structs_composition) section. + +For both structures and classes, the main condition for the admissibility of type casting is that they should be related along the inheritance chain. Types from different branches of the hierarchy or not related at all cannot be cast to each other. + +Casting rules are different for objects (values) and pointers. + +Objects + +An object of one type A can be assigned to an object of another type B if the latter has a constructor that takes a parameter of type A (with variations by value, reference or pointer, but usually of the form B(const A &a)). Such a constructor is also called a conversion constructor. + +In the absence of such an explicit constructor, the compiler will try to use an implicit copy operator, i.e. B::operator=(const B &b), while classes A and B must be in the same inheritance chain for the implicit copy to work. conversion from A to B. If A is inherited from B (including not directly, but indirectly), then the properties added to A will disappear when copied to B. If B is inherited from A, then only that part of the properties that are in A will be copied into it. Such conversions are usually not welcome. + +Also, the implicit copy operator may not always be provided by the compiler. In particular, if the class has fields with the modifier const, copying is considered prohibited (see further along). + +In the script ShapesCasting.mq5, we use the shape class hierarchy to demonstrate object type conversions. In the class Shape, the field type is deliberately made constant, so an attempt to convert (assign) an object Square to an object Rectangle ends with an error compiler with detailed explanations: + +``` +   attempting to reference deleted function 'void Rectangle::operator=(const Rectangle&)' +      function 'void Rectangle::operator=(const Rectangle&)' was implicitly deleted +      because it invokes deleted function 'void Shape::operator=(const Shape&)' +   function 'void Shape::operator=(const Shape&)' was implicitly deleted +      because member 'type' has 'const' modifier + +``` + +According to this message, the copy method Rectangle::operator=(const Rectangle&) was implicitly removed by the compiler (which provides its default implementation) because it uses a similar method in the base class Shape::operator =(const Shape&), which in turn was removed due to the presence of the field type with the modifier const. Such fields can only be set when the object is created, and the compiler does not know how to copy the object under such a restriction. + +By the way, the effect of "deleting" methods is available not only to the compiler but to the application programmer: more about this will be discussed in the [Inheritance control: final and delete](/en/book/oop/classes_and_interfaces/classes_final_delete) section. + +The problem could be solved by removing the modifier const or by providing your own implementation of the assignment operator (in it, the const field is not involved and will save the content with a description of the type: "Rectangle"): + +``` +   Rectangle *operator=(const Rectangle &r) +   { +      coordinates.x = r.coordinates.x; +      coordinates.y = r.coordinates.y; +      backgroundColor = r.backgroundColor; +      dx = r.dx; +      dy = r.dy; +      return &this; +   } + +``` + +Note that this definition returns a pointer to the current object, while the default implementation generated by the compiler was of type void (as seen in the error message). This means that the compiler-provided default assignment operators cannot be used in the chain x = y = z. If you require this capability, override operator= explicitly and return the desired type other than void. + +Pointers + +The most practical is to convert pointers to objects of different types. + +In theory, all options for casting object type pointers can be reduced to three: + +- From base to derived, the downward type casting (downcast), because it is customary to draw a class hierarchy with an inverted tree; +- From derivative to base, the ascending type casting (upcast); and +- Between classes of different branches of the hierarchy or even from different families. + +The last option is forbidden (we will get a compilation error). The compiler allows the first two, but if "upcast" is natural and safe, then "downcast" can lead to runtime errors. + +``` +void OnStart() +{ +   Rectangle *r = addRandomShape(Shape::SHAPES::RECTANGLE); +   Square *s = addRandomShape(Shape::SHAPES::SQUARE); +   Circle *c = NULL; +   Shape *p; +   Rectangle *r2; +    +   // OK +   p = c;   // Circle -> Shape +   p = s;   // Square -> Shape +   p = r;   // Rectangle -> Shape +   r2 = p;  // Shape -> Rectangle +   ... +}; + +``` + +Of course, when a pointer to an object of the base class is used, methods and properties of the derived class cannot be called on it, even if the corresponding object is located at the pointer. We will get an "undeclared identifier" compilation error. + +However, the [explicit cast](/en/book/basis/conversion/conversion_explicit) syntax is supported for pointers (see C-style), which allows the "on the fly" conversion of a pointer to the required type in expressions and its dereferencing without creating an intermediate variable. + +``` +Base *b; +Derived d; +b = &d; +((Derived *)b).derivedMethod(); + +``` + +Here we have created a derived class object (Derived) and a base type pointer to it (Base *). To access the method derivedMethod of a derived class, the pointer is temporarily converted to type Derived. + +An asterisk pointer type must be enclosed in parentheses. In addition, the cast expression itself, including the variable name, is also surrounded by another pair of parentheses. + +Another compilation error ("type mismatch" - "type mismatch") in our test generates a line where we try to cast a pointer to Rectangle to a pointer to Circle: they are from different inheritance branches. + +``` +   c = r; // error: type mismatch + +``` + +Things are much worse when the type of the pointer being cast to does not match the actual object (although their types are compatible, and therefore the program compiles fine). Such an operation will end with an error already at the program execution stage (that is, the compiler cannot catch it). The program is then unloaded. + +For example, in the script ShapesCasting.mq5 we have described a pointer to Square and assigned it a pointer to Shape, which contains the object Rectangle. + +``` +   Square *s2; +   // RUNTIME ERROR +   s2 = p; // error: Incorrect casting of pointers + +``` + +The terminal returns the "Incorrect casting of pointers" error. The pointer of a more specific type Square is not capable of pointing to the parent object Rectangle. + +To avoid runtime troubles and to prevent the program from crashing, MQL5 provides a special language construct dynamic_cast. With this construct, you can "carefully" check whether it is possible to cast a pointer to the required type. If the conversion is possible, then it will be made. And if not, we will get a null pointer (NULL) and we can process it in a special way (for example, using if to somehow initialize or interrupt the execution of the function, but not the entire program). + +The syntax of dynamic_cast is as follows: + +``` +dynamic_cast< Class * >( pointer ) + +``` + +In our case, it is enough to write: + +``` +   s2 = dynamic_cast(p); // trying to cast type, and will get NULL if unsuccessful +   Print(s2); // 0 + +``` + +The program will run as expected. + +In particular, we can try again to cast a rectangle into a circle and make sure that we get 0: + +``` +   c = dynamic_cast(r); // trying to cast type, and will get NULL if unsuccessful +   Print(c); // 0 + +``` + +There is a special pointer type in MQL5 that can store any object. This type has the following notation: void *. + +Let's demonstrate how the variable void * works with dynamic_cast. + +``` +   void *v; +   v = s;   // set to the instance Square +   PRT(dynamic_cast(v)); +   PRT(dynamic_cast(v)); +   PRT(dynamic_cast(v)); +   PRT(dynamic_cast(v)); +   PRT(dynamic_cast(v)); + +``` + +The first three lines will log the value of the pointer (a descriptor of the same object), and the last two will print 0. + +Now, back to the example of the forward declaration in the [Indicators](/en/book/oop/classes_and_interfaces/classes_pointers) section (see file ThisCallback.mq5), where the classes Manager and Element contained mutual pointers. + +The pointer type void * allows you to get rid of the preliminary declaration (ThisCallbackVoid.mq5). Let's comment out the line with it, and change the type of the field owner with a pointer to the manager object to void *. In the constructor, we also change the type of the parameter. + +``` +// class Manager;  +class Element +{ +   void *owner; // looking forward to being compatible with the Manager type * +public: +   Element(void *t = NULL): owner(t) { } // was Element(Manager &t) +   void doMath() +   { +      const int N = 1000000; +       +      // get the desired type at runtime +      Manager *ptr = dynamic_cast(owner); +      // then everywhere you need to check ptr for NULL before using +       +      for(int i = 0; i < N; ++i) +      { +         if(i % (N / 20) == 0) +         { +            if(ptr != NULL) ptr.progressNotify(&this, i * 100.0f / N); +         } +         // ... lots of calculations +      } +      if(ptr != NULL) ptr.progressNotify(&this, 100.0f); +   } +   ... +}; + +``` + +This approach can provide more flexibility but requires more care because dynamic_cast can return NULL. It is recommended, whenever possible, to use standard dispatch facilities (static and dynamic) with control of the types provided by the language. + +Pointers void * usually become necessary in exceptional cases. And the "extra" line with a preliminary description is not the case. It has been used here only as the simplest example of the universality of the pointer void *. diff --git a/skills/mql5/references/book/02-oop/0124-oop-classes-and-interfaces-classes-ref-pointers-const.md b/skills/mql5/references/book/02-oop/0124-oop-classes-and-interfaces-classes-ref-pointers-const.md new file mode 100644 index 0000000..d6dd91a --- /dev/null +++ b/skills/mql5/references/book/02-oop/0124-oop-classes-and-interfaces-classes-ref-pointers-const.md @@ -0,0 +1,199 @@ +# Pointers, references, and const + +After learning about built-in and object types, and the concepts of [reference](/en/book/basis/functions/functions_ref_value) and [pointer](/en/book/oop/classes_and_interfaces/classes_pointers), it probably makes sense to do a comparison of all available type modifications. + +References in MQL5 are used only when describing parameters of functions and methods. Moreover, object type parameters must be passed by reference. + +``` +void function(ClassOrStruct &object) { }          // OK +void function(ClassOrStruct object) { }           // wrong +void function(double &value) { }                  // OK +void function(double value) { }                   // OK + +``` + +Here ClassOrStruct is the name of the class or structure. + +It is allowed to pass only variables (LValue) as an argument for a reference type parameter, but not constants or temporary values obtained as a result of expression evaluation. + +You cannot create a variable of a reference type or return a reference from a function. + +``` +ClassOrStruct &function(void) { return Class(); } // wrong +ClassOrStruct &object;                            // wrong +double &value;                                    // wrong + +``` + +Pointers in MQL5 are available only for class objects. Pointers to variables of built-in types or structures are not supported. + +You can declare a variable or function parameter of type a pointer to an object, and also return a pointer to an object from the function. + +``` +ClassOrStruct *pointer;                                   // OK +void function(ClassOrStruct *object) { }                  // OK +ClassOrStruct *function() { return new ClassOrStruct(); } // OK + +``` + +However, you cannot return a pointer to a local automatic object, because the latter will be freed when the function exits, and the pointer will become invalid. + +If the function returned a pointer to an object dynamically allocated within the function with new, then the calling code must "remember" to free the pointer with delete. + +A pointer, unlike a reference, can be NULL. Pointer parameters can have a default value, but references can't ("reference cannot be initialized" error). + +``` +void function(ClassOrStruct *object = NULL) { }          // OK +void function(ClassOrStruct &object = NULL) { }          // wrong + +``` + +Links and pointers can be combined in a parameter description. So a function can take a reference to a pointer: and then changes to the pointer in the function will become available in the calling code. In particular, the factory function, which is responsible for creating objects, can be implemented in this way. + +``` +void createObject(ClassName *&ref) +{ +   ref = new ClassName(); +   // further customization of ref +   ... +} + +``` + +True, to return a single pointer from a function, it is usually customary to use the return statement, so this example is somewhat artificial. However, in those cases when it is necessary to pass an array of pointers outside, a reference to it in the parameter becomes the preferred option. For example, in some classes of the standard library for working with container classes of the map type with [key, value] pairs (MQL5/Include/Generic/SortedMap.mqh, MQL5/Include/Generic/HashMap.mqh) there are methods CopyTo for getting arrays with elements CKeyValuePair. + +``` +int CopyTo(CKeyValuePair *&dst_array[], const int dst_start = 0); + +``` + +The parameter type dst_array may seem unfamiliar: it's a class template. We will learn about templates in the [next chapter](/en/book/oop/templates). Here, for now, the only important thing for us is that this is a reference to an array of pointers. + +The const modifier imposes special behavior for all types. In relation to built-in types, it was discussed in the section on [Constant variables](/en/book/basis/variables/const_variables). Object types have their own characteristics. + +If a variable or function parameter is declared as a pointer or a reference to an object (a reference is only in the case of a parameter), then the presence of the modifier const on them limits the set of methods and properties that can be accessed to only those that also have the modifier const. In other words, only constant properties are accessible through constant references and pointers. + +When you try to call a non-const method or change a non-const field, the compiler will generate an error: "call non-const method for constant object" or "constant cannot be modified". + +A non-const pointer parameter can take any argument (constant or non-constant). + +It should be borne in mind that two modifiers const can be set in the pointer description: one will refer to the object, and the second to the pointer: + +- Class *pointer is a pointer to an object; the object and the pointer work without limitations; +- const Class *pointer is a pointer to a const object; for the object, only constant methods and reading properties are available, but the pointer can be changed (assigned to it the address of another object); +- const Class * const pointer is a const pointer to a const object; for the object, only const methods and reading properties are available; the pointer cannot be changed; +- Class * const pointer is a const pointer to an object; the pointer cannot be changed, but the properties of the object can be changed. + +Consider the following class Counter (CounterConstPtr.mq5) as an example. + +``` +class Counter +{ +public: +   int counter; +    +   Counter(const int n = 0) : counter(n) { } +    +   void increment() +   { +      ++counter; +   } +    +   Counter *clone() const +   { +      return new Counter(counter); +   } +}; + +``` + +It artificially made the public variable counter. The class also has two methods, one of which is constant (clone), and the second is not (increment). Recall that a constant method does not have the right to change the fields of an object. + +The following function with the Counter *ptr type parameter can call all methods of the class and change its fields. + +``` +void functionVolatile(Counter *ptr) +{ +   // OK: everything is available +   ptr.increment(); +   ptr.counter += 2; +   //remove the clone immediately so that there is no memory leak +   // the clone is only needed to demonstrate calling a constant method  +   delete ptr.clone();  +   ptr = NULL; +} + +``` + +The following function with the parameter const Counter *ptr will throw a couple of errors. + +``` +void functionConst(const Counter *ptr) +{ +   // ERRORS: +   ptr.increment(); // calling non-const method for constant object +   ptr.counter = 1; // constant cannot be modified +    +   // OK: only const methods are available, fields can be read +   Print(ptr.counter); // reading a const object +   Counter *clone = ptr.clone(); // calling a const method +   ptr = clone;     // changing a non-const pointer ptr +   delete ptr;      // cleaning memory +} + +``` + +Finally, the following function with the parameter const Counter * const ptr does even less. + +``` +void functionConstConst(const Counter * const ptr) +{ +   // OK: only const methods are available, the pointer ptr cannot be changed +   Print(ptr.counter); // reading a const object +   delete ptr.clone(); // calling a const method +    +   Counter local(0); +   // ERRORS: +   ptr.increment(); // calling non-const method for constant object +   ptr.counter = 1; // constant cannot be modified +   ptr = &local;    // constant cannot be modified +} + +``` + +In the function OnStart, where we have declared two Counter objects (one is constant and the other is not), you can call these functions with some exceptions: + +``` +void OnStart() +{ +   Counter counter; +   const Counter constCounter; +    +   counter.increment(); +    +   // ERROR: +   // constCounter.increment(); // call non-const method for constant object +   Counter *ptr = (Counter *)&constCounter; // trick: type casting without const +   ptr.increment(); +    +   functionVolatile(&counter); +    +   // ERROR: cannot convert from a const pointer... +   // functionVolatile(&constCounter); // to a non-const pointer +    +   functionVolatile((Counter *)&constCounter); // type casting without const +    +   functionConst(&counter); +   functionConst(&constCounter); +    +   functionConstConst(&counter); +   functionConstConst(&constCounter); +} + +``` + +First, note that variables also generate an error when trying to call a const method increment on a non-const object. + +Secondly, constCounter cannot be passed to the functionVolatile function — we get the error "cannot convert from const pointer to nonconst pointer". + +However, both errors can be circumvented by explicit type casting without the const modifier. Although this is not recommended. diff --git a/skills/mql5/references/book/02-oop/0125-oop-classes-and-interfaces-classes-final-delete.md b/skills/mql5/references/book/02-oop/0125-oop-classes-and-interfaces-classes-final-delete.md new file mode 100644 index 0000000..bd49525 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0125-oop-classes-and-interfaces-classes-final-delete.md @@ -0,0 +1,75 @@ +# Inheritance management: final and delete + +MQL5 allows you to impose some restrictions on the inheritance of classes and structures. + +Keyword final + +By using the final keyword added after the class name, the developer can disable inheritance from that class. For example (FinalDelete.mq5): + +``` +class Base +{ +}; +  +class Derived final : public Base +{ +}; +  +class Concrete : public Derived // ERROR +{ +}; + +``` + +The compiler will throw the error "cannot inherit from 'Derived' as it has been declared as 'final'". + +Unfortunately, there is no consensus on the benefits and scenarios for using such a restriction. The keyword lets users of the class know that its author, for one reason or another, does not recommend taking it as the base one (for example, its current implementation is draft and will change a lot, which may cause potential legacy projects to stop compiling). + +Some people try to encourage the design of programs in this way, in which the inclusion of objects ([composition](/en/book/oop/classes_and_interfaces/classes_composition)) is used instead of inheritance. Excessive passion for inheritance can indeed increase the class cohesion (that is, mutual influence), since all heirs in one way or another can change parent data or methods (in particular, by redefining virtual functions). As a result, the complexity of the working logic of the program and the likelihood of unforeseen side effects increase. + +An additional advantage of using final can be code optimization by the compiler: for pointers of "final" types, it can replace the dynamic dispatch of virtual functions with a static one. + +Keyword delete + +The delete keyword can be specified in the header of a method to make it inaccessible in the current class and its descendants. Virtual methods of parent classes cannot be deleted in this way (this would violate the "contract" of the class, that is, the heirs would cease to "be" ("is a") representatives of the same kind). + +``` +class Base +{ +public: +   void method() { Print(__FUNCSIG__); } +}; +  +class Derived : public Base +{ +public: +   void method() = delete; +}; +  +void OnStart() +{ +   Base *b; +   Derived d; +    +   b = &d; +   b.method(); +    +   // ERROR:    +   // attempting to reference deleted function 'void Derived::method()' +   //    function 'void Derived::method()' was explicitly deleted +   d.method(); +} + +``` + +An attempt to call it will result in a compilation error. + +We saw a similar error in the [Object type casting](/en/book/oop/classes_and_interfaces/classes_dynamic_cast_void) section because the compiler has some intelligence to also "remove" methods under certain conditions. + +It is recommended to mark as deleted the following methods for which the compiler provides implicit implementations: + +- default constructor: Class(void) = delete; +- copy constructor: Class(const Class &object) = delete; +- copy/assign operator: void operator=(const Class &object) = delete. + +If you require any of these, you must define them explicitly. Otherwise, it is considered good practice to abandon the implicit implementation. The thing is that the implicit implementation is quite straightforward and can give rise to problems that are difficult to localize, in particular, when casting object types. diff --git a/skills/mql5/references/book/02-oop/0126-oop-templates.md b/skills/mql5/references/book/02-oop/0126-oop-templates.md new file mode 100644 index 0000000..a3eaa1a --- /dev/null +++ b/skills/mql5/references/book/02-oop/0126-oop-templates.md @@ -0,0 +1,15 @@ +# Templates + +In modern programming languages, there are many built-in features that allow you to avoid code duplication and, thereby, minimize the number of errors and increase programmer productivity. In MQL5, such tools include the already known [functions](/en/book/basis/functions), object types with inheritance support ([classes](/en/book/oop/classes_and_interfaces) and [structures](/en/book/oop/structs_and_unions)), [preprocessor macros](/en/book/basis/preprocessor/preprocessor_define_functional), and the ability to [include files](/en/book/basis/preprocessor/preprocessor_include). But this list would be incomplete without templates. + +A template is a specially crafted generic definition of a function or object type from which the compiler can automatically generate working instances of that function or object type. The resulting instances contain the same algorithm but operate on variables of different types, corresponding to the specific conditions for using the template in the source code. + +For C++ connoisseurs, we note that MQL5 templates do not support many features of C++ templates, in particular: + +- parameters that are not types; +- parameters with default values; +- variable number of parameters; +- specialization of classes, structures, and associations (full and partial); +- templates for templates. + +On the one hand, this reduces the potential of templates in MQL5, but, on the other hand, it simplifies the learning of the material for those who are unfamiliar with these technologies. diff --git a/skills/mql5/references/book/02-oop/0127-oop-templates-templates-header.md b/skills/mql5/references/book/02-oop/0127-oop-templates-templates-header.md new file mode 100644 index 0000000..248845d --- /dev/null +++ b/skills/mql5/references/book/02-oop/0127-oop-templates-templates-header.md @@ -0,0 +1,31 @@ +# Template header + +In MQL5, you can make functions, object types (classes, structures, unions) or separate methods within them templated. In any case, the template description has a title: + +``` +template  + +``` + +The header starts with the template keyword, followed by a comma-separated list of formal parameters in angle brackets: each parameter is denoted by the typename keyword and an identifier. Identifiers must be unique within a particular definition. + +The keyword typename in the template header tells the compiler that the following identifier should be treated as a type. In the future, the MQL5 compiler is likely to support other kinds of non-type parameters, as the C++ compiler does. + +This use of typename should not be confused with the built-in [operator ](/en/book/basis/expressions/operators_sizeof_typename)[typename](/en/book/basis/expressions/operators_sizeof_typename), which returns a string with the type name of the passed argument. + +A template header is followed by a usual definition of a function (method) or class (structure, union), in which the formal parameters of the template (identifiers T, Ti) are used in instructions and expressions in those places where the syntax requires a type name. For example, for template functions, template parameters describe the types of the function parameters or return value, and in a template class, a template parameter can designate a field type. + +A template is an entire definition. A template ends with a definition of an entity (function, method, class, structure, union) preceded by the template heading. + +For template parameter names, it is customary to take one- or two-character identifiers in uppercase. + +The minimum number of parameters is 1, the maximum is 64. + +The main use cases for parameters (using the T parameter as an example) include: + +- type when describing fields, local variables in functions/methods, their parameters and return values ​​(T variable_name; T function(T parameter_name)); +- one of the components of a fully qualified type name, in particular: T::SubType, T.StaticMember; +- construction of new types with modifiers: const T, pointer T *, reference T &, array T[], typedef functions T(*func)(T); +- construction of new template types: T, Type, including when inheriting from templates (see section [Template specialization, which is not present](/en/book/oop/templates/templates_specialization)); +- typecasting (T) with the ability to add modifiers and creating objects via new T(); +- sizeof(T) as a primitive replacement for value parameters that are absent in MQL templates (at the time of writing the book). diff --git a/skills/mql5/references/book/02-oop/0128-oop-templates-templates-principles.md b/skills/mql5/references/book/02-oop/0128-oop-templates-templates-principles.md new file mode 100644 index 0000000..9f88cd6 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0128-oop-templates-templates-principles.md @@ -0,0 +1,102 @@ +# General template operation principles + +Let's recall [functions overload](/en/book/basis/functions/functions_overloading). It consists in defining several versions of a function with different parameters, including situations when the number of parameters is the same, but their types are different. Often an algorithm of such functions is the same for parameters of different types. For example, MQL5 has a built-in function [MathMax](/en/book/common/maths/maths_max_min) that returns the largest of the two values passed to it: + +``` +double MathMax(double value1, double value2); + +``` + +Although a prototype is only provided for the type double, the function is actually capable of working with argument pairs of other numeric types, such as int or datetime. In other words, the function is an overloaded kernel for built-in numerical types. If we wanted to achieve the same effect in our source code, we would have to overload the function by duplicating it with different parameters, like so: + +``` +double Max(double value1, double value2) +{ +   return value1 > value2 ? value1 : value2; +} +  +int Max(int value1, int value2) +{ +   return value1 > value2 ? value1 : value2; +} +  +datetime Max(datetime value1, datetime value2) +{ +   return value1 > value2 ? value1 : value2; +} + +``` + +All implementations (function bodies) are the same. Only the parameter types change. + +This is when templates are useful. By using them, we can describe one sample of the algorithm with the required implementation, and the compiler itself will generate several instances of it for the specific types involved in the program. Generation occurs on the fly during compilation and is imperceptible to the programmer (unless there is an error in the template) The source code obtained automatically is not inserted into the program text, but is directly converted into binary code (ex5 file). + +In the template, one or more parameters are formal designations of types, for which, at the compilation stage, according to special type inference rules, real types will be selected from among built-in or user-defined ones. For example, the Max function can be described using the following template with the T type parameter: + +``` +template +T Max(T value1, T value2) +{ +   return value1 > value2 ? value1 : value2; +} + +``` + +And then - apply it for variables of various types (see TemplatesMax.mq5): + +``` +void OnStart() +{ +   double d1 = 0, d2 = 1; +   datetime t1 = D'2020.01.01', t2 = D'2021.10.10'; +   Print(Max(d1, d2)); +   Print(Max(t1, t2)); +   ... +} + +``` + +In this case, the compiler will automatically generate variants of the function Max for the types double and datetime. + +The template itself does not generate source code. To do this, you need to create an instance of the template in one way or another: call a template function or mention the name of a template class with specific types to create an object or a derived class. + +Until this is done, the entire pattern is ignored by the compiler. For example, we can write the following supposedly template function, which actually contains syntactically incorrect code. However, the compilation of a module with this function will succeed as long as it is not called anywhere. + +``` +template +void function() +{ +  it's not a comment, but it's not source code either +   !%^&* +} + +``` + +For each use of the template, the compiler determines the real types that match the formal parameters of the template. Based on this information, template source code is automatically generated for each unique combination of parameters. This is the instance. + +So, in the given example of the Max function, we called the template function twice: for the pair of variables of type double, and for the pair of variables of type datetime. This resulted in two instances of the Max function with source code for the matches T=double and T=datetime. Of course, if the same template is called in other parts of the code for the same types, no new instances will be generated. A new instance of the template is required only if the template is applied to another type (or set of types, if there is more than 1 parameter). + +Please note that the template Max has one parameter, and it sets the type for two input parameters of the function and its return value at once. In other words, the template declaration is capable of imposing certain restrictions on the types of valid arguments. + +If we were to call Max on variables of different types, the compiler would not be able to determine the type to instantiate the template and would throw the error "ambiguous template parameters, must be 'double' or 'datetime'": + +``` +Print(Max(d1, t1)); // template parameter ambiguous, +                    // could be 'double' or 'datetime' + +``` + +This process of discovering the actual types for template parameters based on the context in which the template is used is called type deduction. In MQL5, type inference is available only for function and method templates. + +For classes, structures, and unions, a different way of binding types to template parameters is used: the required types are explicitly specified in angle brackets when creating a template instance (if there are several parameters, then the corresponding number of types is indicated as a comma-separated list). For more on this, see the section [Object type templates](/en/book/oop/templates/templates_objects). + +The same explicit method can be applied to functions as an alternative to automatic type inference. + +For example, we can generate and call an instance of Max for type ulong: + +``` +Print(Max(1000, 10000000)); + +``` + +In this case, if not for the explicit indication, the template function would be associated with the type int (based on the values ​​of integer constants). diff --git a/skills/mql5/references/book/02-oop/0129-oop-templates-templates-vs-macro.md b/skills/mql5/references/book/02-oop/0129-oop-templates-templates-vs-macro.md new file mode 100644 index 0000000..029cfd9 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0129-oop-templates-templates-vs-macro.md @@ -0,0 +1,28 @@ +# Templates vs preprocessor macros + +A question may arise at some point, is it possible to use macro substitutions for the purposes of code generation? It is actually possible. For example, the set of Max functions can be easily represented as a macro: + +``` +#define MAX(V1,V2) ((V1) > (V2) ? (V1) : (V2)) + +``` + +However, macros have more limited capabilities (nothing more than text substitution) and therefore they are only used in simple cases (like the one above). + +When comparing macros and templates, the following differences should be noted. + +Macros are "expanded" and replaced in the source text by the preprocessor before compilation starts. At the same time, there is no information about the types of parameters and the context in which the contents of the macro are substituted. In particular, the macro MAX cannot provide a check-up that the types of the parameters V1 and V2 are the same, and also that the comparison operator '>' is defined for them. In addition, if a variable with the name MAX is encountered in a program text, the preprocessor will try to substitute the "call" of the MAX macro in its place and will be "unhappy" with the absence of arguments. Worse yet, these substitutions ignore which namespaces or classes the MAX token is found in – basically, any will do. + +Unlike macros, templates are handled by the compiler in terms of specific argument types and where they are used, so they provide type compatibility (and general applicability) checks for all expressions in a template, as well as context binding. For example, we can define a method template within a concrete class. + +A template with the same name can be defined differently for different types if necessary, while a macro with a given name is always replaced by the same "implementation". For example, in the case of a function like MAX, we could define a case-insensitive comparison for strings. + +Compilation errors due to problems in macros are difficult to diagnose, especially if the macro consists of several lines, since the problematic line with the "call" of the macro is highlighted "as is", without the expanded version of the text, as it came from the preprocessor to the compiler. + +At the same time, templates are elements of the source code in a ready-made form, as they enter the compiler, and therefore any error in them has a specific line number and position in the line. + +Macros can have side effects, which we discussed in the [Form of #define as a pseudo-function](/en/book/basis/preprocessor/preprocessor_define_functional) section: if the MAX macro arguments are expressions with increments/decrements, then they will be executed twice. + +However, macros also have some advantages. Macros are capable of generating any text, not just correct language constructs. For example, with a few macros, you can simulate the instruction switch for strings (although this approach is not recommended). + +In the standard library, macros are used, in particular, to organize the processing of events on charts (see MQL5/Include/Controls/Defines.mqh: EVENT_MAP_BEGIN, EVENT_MAP_END, ON_EVENT, etc.). It will not work on templates, but the way of arranging an event map on macros, of course, is far from the only one and not the most convenient for debugging. It is difficult to debug step-by-step (line-by-line) code execution in macros. Templates, on the contrary, support debugging in full. diff --git a/skills/mql5/references/book/02-oop/0130-oop-templates-templates-for-standard-and-object-types.md b/skills/mql5/references/book/02-oop/0130-oop-templates-templates-for-standard-and-object-types.md new file mode 100644 index 0000000..aadc219 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0130-oop-templates-templates-for-standard-and-object-types.md @@ -0,0 +1,177 @@ +# Features of built-in and object types in templates + +It should be kept in mind that 3 important aspects impose restrictions on the applicability of types in a template: + +- Whether the type is built-in or user-defined (user-defined types require parameters to be passed by reference, and built-in ones will not allow a literal to be passed by reference); +- Whether the object type is a class (only classes support pointers); +- A set of operations performed on data of the appropriate types in the template algorithm. + +Let's say we have a Dummy structure (see script TemplatesMax.mq5): + +``` +struct Dummy +{ +   int x; +}; + +``` + +If we try to call the Max function for two instances of the structure, we will get a bunch of error messages, with mains as the following: "objects can only be passed by reference" and "you cannot apply a template." + +``` +   // ERRORS: +   // 'object1' - objects are passed by reference only +   // 'Max' - cannot apply template +   Dummy object1, object2; +   Max(object1, object2); + +``` + +The pinnacle of the problem is passing template function parameters by value, and this method is incompatible with any object type. To solve it, you can change the type of parameters to links: + +``` +template +T Max(T &value1, T &value2) +{ +   return value1 > value2 ? value1 : value2; +} + +``` + +The old error will go away, but then we will get a new error: "'>' - illegal operation use" ("'>' - illegal operation use"). The point is that the Max template has an expression with the '>' comparison operator. Therefore, if a custom type is substituted into the template, the '>' operator must be overloaded in the template (and the structure Dummy does not have it: we'll get to that shortly). For more complex functions, you will likely need to overload a much larger number of operators. Fortunately, the compiler tells you exactly what is missing. + +However, changing the method of passing function parameters by reference additionally led to the previous call not working as such: + +``` +Print(Max(1000, 10000000)); + +``` + +Now it generates errors: "parameter passed as reference, variable expected". Thus, our function template stopped working with literals and other temporary values ​​(in particular, it is impossible to directly pass an expression or the result of calling another function into it). + +One might think that the universal way out of the situation would be template function overloading, i.e., the definition of both options, that differs only in the ampersand in the parameters: + +``` +template +T Max(T &value1, T &value2) +{ +   return value1 > value2 ? value1 : value2; +} +   +template +T Max(T value1, T value2) +{ +   return value1 > value2 ? value1 : value2; +} + +``` + +But it won't work. Now the compiler throws the error "ambiguous function overload with the same parameters": + +``` +'Max' - ambiguous call to overloaded function with the same parameters +could be one of 2 function(s) +   T Max(T&,T&) +   T Max(T,T) + +``` + +The final, working overload would require the modifier const to be added to the links. Along the way, we added the operator Print to the template Max so that we can see in the log which overload is being called and which parameter type T corresponds to. + +``` +template +T Max(const T &value1, const T &value2) +{ +   Print(__FUNCSIG__, " T=", typename(T)); +   return value1 > value2 ? value1 : value2; +} +    +template +T Max(T value1, T value2) +{ +   Print(__FUNCSIG__, " T=", typename(T)); +   return value1 > value2 ? value1 : value2; +} +    +struct Dummy +{ +   int x; +   bool operator>(const Dummy &other) const +   { +      return x > other.x; +   } +}; + +``` + +We have also implemented an overload of the operator '>' in the Dummy structure. Therefore, all Max function calls in the test script are completed successfully: both for built-in and user-defined types, as well as for literals and variables. The outputs that go into the log: + +``` +double Max(double,double) T=double +1.0 +datetime Max(datetime,datetime) T=datetime +2021.10.10 00:00:00 +ulong OnStart::Max(ulong,ulong) T=ulong +10000000 +Dummy Max(const Dummy&,const Dummy&) T=Dummy + +``` + +An attentive reader will notice that we now have two identical functions that differ only in the way parameters are passed (by value and by reference), and this is exactly the situation against which the use of templates is directed. Such duplication can be costly if the function body is not as simple as ours. This can be solved by the usual methods: separate the implementation into a separate function and call it from both "overloads", or call one "overload" from the other (an optional parameter was required to avoid the first version of Max calling itself and, resulting in stack overflows): + +``` +template +T Max(T value1, T value2) +{ +   // calling a function with parameters by reference +   return Max(value1, value2, true); +} +    +template +T Max(const T &value1, const T &value2, const bool ref = false) +{ +   return (T)(value1 > value2 ? value1 : value2); +} + +``` + +We still have to consider one more point associated with user-defined types, namely the use of pointers in templates (recall, that they apply only to class objects). Let's create a simple class Data and try to call the template function Max for pointers to its objects. + +``` +class Data +{ +public: +   int x; +   bool operator>(const Data &other) const +   { +      return x > other.x; +   } +}; +    +void OnStart() +{ +   ...  +   Data *pointer1 = new Data(); +   Data *pointer2 = new Data(); +   Max(pointer1, pointer2); +   delete pointer1; +   delete pointer2; +} + +``` + +We will see in the log that 'T=Data*', i.e. the pointer attribute, hits the inline type. This suggests that, if necessary, you can write another overload of the template function, which will be responsible only for pointers. + +``` +template +T *Max(T *value1, T *value2) +{ +   Print(__FUNCSIG__, " T=", typename(T)); +   return value1 > value2 ? value1 : value2; +} + +``` + +In this case, the attribute of the pointer '*' is already present in the template parameters, and so type inference results in 'T=Data'. This approach allows you to provide a separate template implementation for pointers. + +If there are multiple templates that are suitable for generating an instance with specific types, the most specialized version of the template is chosen. In particular, when calling the function Max with pointer arguments, two templates with parameters T (T=Data*) and T* (T=Data), but since the former can take both values ​​and pointers, it is more general than the latter, which only works with pointers. Therefore, the second one will be chosen for pointers. In other words, the fewer modifiers in the actual type that is substituted for T, the more preferable the template variant. In addition to the attribute of the pointer '*', this also includes the modifier const. The parameters const T* or const T are more specialized than just T* or T, respectively. diff --git a/skills/mql5/references/book/02-oop/0131-oop-templates-templates-functions.md b/skills/mql5/references/book/02-oop/0131-oop-templates-templates-functions.md new file mode 100644 index 0000000..48fc14b --- /dev/null +++ b/skills/mql5/references/book/02-oop/0131-oop-templates-templates-functions.md @@ -0,0 +1,225 @@ +# Function templates + +A function template consists of a header with template parameters (the syntax was described [earlier](/en/book/oop/templates/templates_header)) and a function definition in which the template parameters denote arbitrary types. + +As a first example, consider the function Swap for swapping two array elements (TemplatesSorting.mq5). The template parameter T is used as the type of the input array variable, as well as the type of the local variable temp. + +``` +template +void Swap(T &array[], const int i, const int j) +{ +   const T temp = array[i]; +   array[i] = array[j]; +   array[j] = temp; +} + +``` + +All statements and expressions in the body of the function must be applicable to real types, for which the template will then be instantiated. In this case, the assignment operator '=' is used. While it always exists for built-in types, it may need to be explicitly overloaded for user-defined types. + +The compiler generates the implementation of the copy operator for classes and structures by default, but it can be removed implicitly or explicitly (see keyword [delete](/en/book/oop/classes_and_interfaces/classes_final_delete)). In particular, as we saw in the section [Object Type Casting](/en/book/oop/classes_and_interfaces/classes_dynamic_cast_void), having a constant field in a class causes the compiler to remove its implicit copy option. Then the above template function Swap cannot be used for objects of this class: the compiler will generate an error. + +For classes/structures that the Swap function works with, it is desirable to have not only an assignment operator but also a copy constructor, because the declaration of the variable temp is actually a construction with an initialization, not an assignment. With a copy constructor, the first line of the function is executed in one go (temp is created based on array[i]), while without it, the default constructor will be called first, and then for temp the operator '=' will be executed. + +Let's see how the template function Swap can be used in the quicksort algorithm: another template function QuickSort implements it. + +``` +template +void QuickSort(T &array[], const int start = 0, int end = INT_MAX) +{ +   if(end == INT_MAX) +   { +      end = start + ArraySize(array) - 1; +   } +   if(start < end) +   { +      int pivot = start; +       +      for(int i = start; i <= end; i++) +      { +         if(!(array[i] > array[end])) +         { +            Swap(array, i, pivot++); +         } +      } +       +      --pivot; +    +      QuickSort(array, start, pivot - 1); +      QuickSort(array, pivot + 1, end); +   } +} + +``` + +Note that the T parameter of the QuickSort template specifies the type of the input parameter array, and this array is then passed to the Swap template. Thus, type inference T for the QuickSort template will automatically determine the type T for the Swap template. + +The built-in function ArraySize (like many others) is able to work with arrays of arbitrary types: in a sense, it is also a template, although it is implemented directly in the terminal. + +Sorting is done thanks to the '>' comparison operator in the if statement. As we noted earlier, this operator must be defined for any type T that is being sorted, because it applies to the elements of an array of type T. + +Let's check how sorting works for arrays of built-in types. + +``` +void OnStart() +{ +   double numbers[] = {34, 11, -7, 49, 15, -100, 11}; +   QuickSort(numbers); +   ArrayPrint(numbers); +   // -100.00000 -7.00000 11.00000 11.00000 15.00000 34.00000 49.00000 +    +   string messages[] = {"usd", "eur", "jpy", "gbp", "chf", "cad", "aud", "nzd"}; +   QuickSort(messages); +   ArrayPrint(messages); +   // "aud" "cad" "chf" "eur" "gbp" "jpy" "nzd" "usd" +} + +``` + +Two calls to the template function QuickSort automatically infer the type of T based on the types of the passed arrays. As a result, we will get two instances of QuickSort for types double and string. + +To check the sorting of a custom type, let's create an ABC structure with an integer field x, and fill it with random numbers in the constructor. It is also important to overload the operator '>' in the structure. + +``` +struct ABC +{ +   int x; +   ABC() +   { +      x = rand(); +   } +   bool operator>(const ABC &other) const +   { +      return x > other.x; +   } +}; +void OnStart() +{ +   ... +   ABC abc[10]; +   QuickSort(abc); +   ArrayPrint(abc); +  /* Sample output: +            [x] +      [0]  1210 +      [1]  2458 +      [2] 10816 +      [3] 13148 +      [4] 15393 +      [5] 20788 +      [6] 24225 +      [7] 29919 +      [8] 32309 +      [9] 32589 +   */ +} + +``` + +Since the structure values are randomly generated, we will get different results, but they will always be sorted in ascending order. + +In this case, the type T is also automatically inferred. However, in some cases, explicit specification is the only way to pass a type to a function template. So, if a template function must return a value of a unique type (different from the types of its parameters) or if there are no parameters, then it can only be specified explicitly. + +For example, the following template function createInstance requires the type to be explicitly specified in the calling instruction, since it is not possible to automatically "calculate" the type T from the return value. If this is not done, the compiler generates a "template mismatch" error. + +``` +class Base +{ +   ... +}; +    +template +T *createInstance() +{ +   T *object = new T(); //calling the constructor +   ...                  //object setting +   return object;  +} +    +void OnStart() +{ +   Base *p1 = createInstance();       // error: template mismatch +   Base *p2 = createInstance(); // ok, explicit directive +   ... +} + +``` + +If there are several template parameters, and the type of the return value is not bound to any of the input parameters of the function, then you also need to specify a specific type when calling: + +``` +template +T MyCast(const U u) +{ +   return (T)u; +} +    +void OnStart() +{ +   double d = MyCast("123.0"); +   string f = MyCast(123.0); +} + +``` + +Note that if the types for the template are explicitly specified, then this is required for all parameters, even though the second parameter U could be inferred from the passed argument. + +After the compiler has generated all instances of the template function, they participate in the standard procedure for choosing the best candidate from all [function overloads](/en/book/basis/functions/functions_overloading) with the same name and the appropriate number of parameters. Of all the overload options (including the created template instances), the closest one in terms of types (with the least number of conversions) is selected. + +If a template function has some input parameters of specific types, then it is considered a candidate only if these types completely match the arguments: any need for conversion will cause the template to be "discarded" as unsuitable. + +Non-template overloads take precedence over template overloads, more specialized ("narrowly focused") "win" from template overloads. + +If the template argument (type) is specified explicitly, then the rules for [implicit type casting](/en/book/basis/conversion/conversion_implicit) are applied for the corresponding function argument (passed value), if necessary, if these types differ. + +If several variants of a function match equally, we will get an "ambiguous call to an overloaded function with the same parameters" error. + +For example, if in addition to the template MyCast, a function is defined to convert a string to a boolean type: + +``` +bool MyCast(const string u) +{ +   return u == "true"; +} + +``` + +then calling MyCast("123.0") will start throwing the indicated error, because the two functions differ only in the return value: + +``` +'MyCast' - ambiguous call to overloaded function with the same parameters +could be one of 2 function(s) +   double MyCast(const string) +   bool MyCast(const string) + +``` + +When describing template functions, it is recommended to include all template parameters in the function parameters. Types can only be inferred from arguments, not from the return value. + +If a function has a templated type parameter T with a default value, and the corresponding argument is omitted when called, then the compiler will also fail to infer the type of T and throw a "cannot apply template" error. + +``` +class Base +{ +public: +   Base(const Base *source = NULL) { } +   static Base *type; +}; +    +static Base* Base::type; +    +template +T *createInstanceFrom(T *origin = NULL) +{ +   T *object = new T(origin); +   return object;  +} +    +void OnStart() +{ +   Base *p1 = createInstanceFrom();   // error: cannot to apply template +   Base *p2 = createInstanceFrom(Base::type); // ok, auto-detect from argument +   Base *p3 = createInstanceFrom();     // ok, explicit directive, an argument is omitted +} + +``` diff --git a/skills/mql5/references/book/02-oop/0132-oop-templates-templates-objects.md b/skills/mql5/references/book/02-oop/0132-oop-templates-templates-objects.md new file mode 100644 index 0000000..695df69 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0132-oop-templates-templates-objects.md @@ -0,0 +1,190 @@ +# Object type templates + +An object type template definition begins with a header containing typed parameters (see section [Template Header](/en/book/oop/templates/templates_header)), and the usual definition of a class, structure, or union. + +``` +template  +class class_name +{ +   ... +}; + +``` + +The only difference from the standard definition is that template parameters can occur in a block of code, in all syntactic constructs of the language, where it is permissible to use a type name. + +Once a template is defined, working instances of it are created when the variables of the template type are declared in the code, specifying the specific types in angle brackets: + +``` +ClassName object; +StructName struct; +ClassName *pointer = new ClassName(); +ClassName1> object; + +``` + +Unlike when calling template functions, the compiler is not able to infer actual types for object templates on its own. + +Declaring a template class/structure variable is not the only way to instantiate a template. An instance is also generated by the compiler if a template type is used as the base type for another, specific (non-template) class or structure. + +For example, the following class Worker, even if empty, is an implementation of Base for type double: + +``` +class Worker : Base +{ +}; + +``` + +This minimum definition is enough (with allowance for adding constructors if the class Base requires them) to start compiling and validating the template code. + +In the [Dynamic object creation](/en/book/oop/classes_and_interfaces/classes_new_delete_pointers) section, we got acquainted with the concept of a dynamic pointer to an object obtained using the operator new. This flexible mechanism has one drawback: pointers need to be monitored and "manually" deleted when they are no longer needed. In particular, when exiting a function or block of code, all local pointers must be cleared with a call delete. + +To simplify the solution to this problem, let's create a template class AutoPtr (TemplatesAutoPtr.mq5, AutoPtr.mqh). Its parameter T is used to describe the field ptr, which stores a pointer to an object of an arbitrary class. We will receive the pointer value through the constructor parameter (T *p) or in the overloaded operator '='. Let's entrust the main work to the destructor: in the destructor, the pointer will be deleted together with the object AutoPtr (the static helper method free is allocated for this). + +The principle of operation of AutoPtr is simple: a local object of this class will be automatically destroyed upon exiting the block where it is described, and if it was previously instructed to "follow" some pointer, then AutoPtr will free it too. + +``` +template +class AutoPtr +{ +private: +   T *ptr; +    +public: +   AutoPtr() : ptr(NULL) { } +    +   AutoPtr(T *p) : ptr(p) +   { +      Print(__FUNCSIG__, " ", &this, ": ", ptr); +   } +    +   AutoPtr(AutoPtr &p) +   { +      Print(__FUNCSIG__, " ", &this, ": ", ptr, " -> ", p.ptr); +      free(ptr); +      ptr = p.ptr; +      p.ptr = NULL; +   } +    +   ~AutoPtr() +   { +      Print(__FUNCSIG__, " ", &this, ": ", ptr); +      free(ptr); +   } +    +   T *operator=(T *n) +   { +      Print(__FUNCSIG__, " ", &this, ": ", ptr, " -> ", n); +      free(ptr); +      ptr = n; +      return ptr; +   } +    +   T* operator[](int x = 0) const +   { +      return ptr; +   } +    +   static void free(void *p) +   { +      if(CheckPointer(p) == POINTER_DYNAMIC) delete p; +   } +}; + +``` + +Additionally, the class AutoPtr implements a copy constructor (more precisely, a jump constructor, since the current object becomes the owner of the pointer), which allows you to return an AutoPtr instance along with a controlled pointer from a function. + +To test the performance of AutoPtr, we will describe a fictitious class Dummy. + +``` +class Dummy +{ +   int x; +public: +   Dummy(int i) : x(i) +   { +      Print(__FUNCSIG__, " ", &this); +   } +   ... +   int value() const +   { +      return x; +   } +}; + +``` + +In the script, in the OnStart function, enter the variable AutoPtr and get the value for it from the function generator. In the function generator itself, we will also describe the object AutoPtr and sequentially create and "attach" two dynamic objects Dummy to it (to check the correct release memory from the "old" object). + +``` +AutoPtr generator() +{ +   AutoPtr ptr(new Dummy(1)); +   // pointer to 1 will be freed after execution of '=' +   ptr = new Dummy(2); +   return ptr; +} +    +void OnStart() +{ +   AutoPtr ptr = generator(); +   Print(ptr[].value());             // 2 +} + +``` + +Since all the main methods log object descriptors (both AutoPtr and controlled pointers ptr), we can track all "transformations" of pointers (for convenience, all lines are numbered). + +``` +01 Dummy::Dummy(int) 3145728 +02  AutoPtr::AutoPtr(Dummy*) 2097152: 3145728 +03  Dummy::Dummy(int) 4194304 +04  Dummy*AutoPtr::operator=(Dummy*) 2097152: 3145728 -> 4194304 +05  Dummy::~Dummy() 3145728 +06  AutoPtr::AutoPtr(AutoPtr&) 5242880: 0 -> 4194304 +07  AutoPtr::~AutoPtr() 2097152: 0 +08  AutoPtr::AutoPtr(AutoPtr&) 1048576: 0 -> 4194304 +09  AutoPtr::~AutoPtr() 5242880: 0 +10  2 +11  AutoPtr::~AutoPtr() 1048576: 4194304 +12  Dummy::~Dummy() 4194304 + +``` + +Let's digress for a moment from the templates and describe in detail how the utility works because such a class can be useful to many. + +  + +Immediately after starting OnStart, the function generator is called. It must return a value to initialize the object AutoPtr in OnStart, and therefore its constructor has not yet been called. Line 02 creates an object AutoPtr#2097152 inside the function generator and gets a pointer to the first Dummy#3145728. Next, a second instance of Dummy#4194304 is created (line 03), which replaces the previous copy with descriptor 3145728 (line 04) in AutoPtr#2097152, and the old copy is deleted (line 05). Line 06 creates a temporary AutoPtr#5242880 to return the value from the generator, and deletes the local one (07). On line 08, the copy constructor for the AutoPtr#1048576 object in the function OnStart is finally used, and the pointer from the temporary object (which is immediately deleted on line 09) is transferred to it. Next, we call Print with the content of the pointer. When the OnStart completes, the destructor AutoPtr (11) automatically fires, causing us to also delete the work object Dummy (12). + +Template technology makes the class AutoPtr a parameterized manager of dynamically allocated objects. But since AutoPtr has a field T *ptr, it only applies to classes (more precisely, pointers to class objects). For example, trying to instantiate a template for a string (AutoPtr s) will result in a lot of errors in the template text, the meaning of which is that the string type does not support pointers. + +This is not a problem here, since the purpose of this template is limited to classes, but for more general templates, this nuance should be kept in mind (see the sidebar). + +Pointers and references + +  + +Please note that the T * construct cannot appear in templates that you plan to use, including for built-in types or structures. The point is that pointers in MQL5 are allowed only for classes. This is not to say that a template cannot in theory be written to apply to both built-in and user-defined types, but it may require some tweaking. It will probably be necessary either to abandon some of the functionality or to sacrifice a level of genericity of the template (make several templates instead of one, overload functions, etc.). + +  + +The most straightforward way to "inject" a pointer type into a template is to include the modifier '*' along with the actual type when the template is instantiated (i.e. it must match T=Type*). However, some functions (such as CheckPointer), operators (such as delete), and syntactic constructs (such as casting ((T)variable)) are sensitive to whether their arguments/operands are pointers or not. Because of this, the same template text is not always syntactically correct for both pointers and simple type values. + +  + +Another significant type difference to keep in mind: objects are passed to methods by reference only, but literals (constants) of simple types cannot be passed by reference. Because of this, the presence or absence of an ampersand may be treated as an error by the compiler, depending on the inferred type of T. As one of the "workarounds", you can optionally "wrap" argument constants into objects or variables. + +  + +Another trick involves using template methods. We will see it in the next section. + +It should be noted that object-oriented techniques go well with patterns. Since a pointer to a base class can be used to store an object of a derived class, AutoPtr is applicable to objects of any derived Dummy classes. + +In theory, this "hybrid" approach is widely used in the container classes (vector, queue, map, list, etc.), which, as a rule, are templates. Container classes may, depending on the implementation, impose additional requirements on the template parameter, in particular, that the inline type must have a copy constructor and an assignment (copy) operator. + +The MQL5 standard library supplied with MetaTrader 5 contains many ready-made templates from this series: Stack.mqh, Queue.mqh, HashMap.mqh, LinkedList.mqh, RedBlackTree.mqh, and others. They are all located in the MQL5/Include/Generic directory. True, they do not provide control over dynamic objects (pointers). + +We'll look at our own example of a simple container class in [Method templates](/en/book/oop/templates/templates_methods). diff --git a/skills/mql5/references/book/02-oop/0133-oop-templates-templates-methods.md b/skills/mql5/references/book/02-oop/0133-oop-templates-templates-methods.md new file mode 100644 index 0000000..98421fa --- /dev/null +++ b/skills/mql5/references/book/02-oop/0133-oop-templates-templates-methods.md @@ -0,0 +1,301 @@ +# Method templates + +Not only an object type as a whole can be a template, but its method separately — simple or static — also can be a template. The exception is virtual methods: they cannot be made templates. It follows that template methods cannot be declared inside [interfaces](/en/book/oop/classes_and_interfaces/classes_abstract_interfaces). However, interfaces themselves can be made templates, and virtual methods can be present in class templates. + +When a method template is contained within a class/structure template, the parameters of both templates must be different. If there are multiple template methods, their parameters are not related in any way and may have the same name. + +A method template is declared similar to a [function template](/en/book/oop/templates/templates_functions), but only in the context of a class, structure, or union (which may or may not be templates). + +``` +[ template < typename T ⌠, typename Ti ...] > ] +class class_name +{ +   ... +   template < typename U [, typename Ui ...] > +  type method_name(parameters_with_types_T_and_U) +   { +   } +}; + +``` + +Parameters, the return value, and the method body can use types T (general for a class) and U (specific for a method). + +An instance of a method for a specific combination of parameters is generated only when it is called in the program code. + +In the previous section, we described the template class AutoPtr for storing and releasing a single pointer. When there are many pointers of the same type, it is convenient to put them in a container object. Let's create a simple template with similar functionality — the class SimpleArray (SimpleArray.mqh). In order not to duplicate the functionality for controlling the release of dynamic memory, we will put in the class contract that it is intended for storing values and objects, but not pointers. To store the pointers, we will place them in AutoPtr objects, and those in the container. + +This has another positive effect: because the object AutoPtr is small, it is easy to copy (without overspending resources on it), which often happens when data is exchanged between functions. The objects of those application classes that AutoPtr points to can be large, and it is not even necessary to implement their own copy constructor in them. + +Of course, it's cheaper to return pointers from functions, but then you need to reinvent the means of memory release control. Therefore, it is easier to use a ready-made solution in the form of AutoPtr. + +For objects inside the container, we will create the data array of the templated type T. + +``` +template +class SimpleArray +{ +protected: +   T data[]; +   ... + +``` + +Since one of the main operations for a container is to add an element, let's provide a helper function to expand the array. + +``` +   int expand() +   { +      const int n = ArraySize(data); +      ArrayResize(data, n + 1); +      return n; +   } + +``` + +We will directly add elements through the overloaded operator '<<'. It uses the generic template parameter T. + +``` +public: +   SimpleArray *operator<<(const T &r) +   { +      data[expand()] = (T)r; +      return &this; +   } + +``` + +This option takes a value by reference, i.e. a variable or an object. You should pay attention to this for now, and why this is important will become clear in a couple of moments. + +Reading elements is done by overloading the operator '[]' (it has the highest precedence and therefore does not require the use of parentheses in expressions). + +``` +   T operator[](int i) const +   { +      return data[i]; +   } + +``` + +First, let's make sure that the class works on the example of the structure. + +``` +struct Properties +{ +   int x; +   string s; +}; + +``` + +To do this, we will describe a container for the structure in the function OnStart and place one object (TemplatesSimpleArray.mq5) into it. + +``` +void OnStart() +{ +   SimpleArray arrayStructs; +   Properties prop = {12345, "abc"}; +   arrayStructs << prop; +   Print(arrayStructs[0].x, " ", arrayStructs[0].s); +   ... +} + +``` + +Debug logging allows you to verify that the structure is in a container. + +Now let's try to store some numbers in the container. + +``` +   SimpleArray arrayNumbers; +   arrayNumbers << 1.0 << 2.0 << 3.0; + +``` + +Unfortunately, we will get "parameter passed as reference, variable expected" errors, which occur exactly in the overloaded operator '<<'. + +We need an overload with parameter passing by value. However, we can't just write a similar method that doesn't have const and '&': + +``` +   SimpleArray *operator<<(T r) +   { +      data[expand()] = (T)r; +      return &this; +   } + +``` + +If you do this, the new variant will lead to an uncompilable template for object types: after all, objects need to be passed only by reference. Even if the function is not used for objects, it is still present in the class. Therefore, we will define the new method as a template with its own parameter. + +``` +template +class SimpleArray +{ +   ... +   template +   SimpleArray *operator<<(U u) +   { +      data[expand()] = (T)u; +      return &this; +   } + +``` + +It will appear in the class only if something by value is passed to the operator '<<', which means it is definitely not an object. True, we cannot guarantee that T and U are the same, so an explicit cast (T)u is performed. For built-in types (if the two types do not match), in some combinations, conversion with loss of precision is possible, but the code will compile for sure. The only exception is the prohibition on converting a string to a boolean type, but it is unlikely that the container will be used for the array bool, so this restriction is not significant. Those who wish can solve this problem. + +With the new template method, the container SimpleArray works as expected and does not conflict with SimpleArray because the two template instances have differences in the generated source code. + +Finally, let's check the container with objects AutoPtr. To do this, let's prepare a simple class Dummy that will "supply" objects for pointers inside AutoPtr. + +``` +class Dummy +{ +   int x; +public: +   Dummy(int i) : x(i) { } +   int value() const +   { +      return x; +   } +}; + +``` + +Inside the functionOnStart, let's create a container SimpleArray> and fill it. + +``` +void OnStart() +{ +   SimpleArray> arrayObjects; +   AutoPtr ptr = new Dummy(20); +   arrayObjects << ptr; +   arrayObjects << AutoPtr(new Dummy(30)); +   Print(arrayObjects[0][].value()); +   Print(arrayObjects[1][].value()); +} + +``` + +Recall that in AutoPtr the operator '[]' is used to return a stored pointer, so arrayObjects[0][] means: return the 0th element of the array data into SimpleArray, i.e. the object AutoPtr, and then the second pair of square brackets is applied to the volume, resulting in a pointer Dummy*. Next, we can work with all the properties of this object: in this case, we retrieve the current value of the x field. + +Because Dummy does not have a copy constructor, you cannot use a container to store these objects directly without AutoPtr. + +``` +   // ERROR: +   // object of 'Dummy' cannot be returned, +   // copy constructor 'Dummy::Dummy(const Dummy &)' not found +   SimpleArray bad; + +``` + +But a resourceful user can guess how to get around this. + +``` +   SimpleArray bad; +   bad << new Dummy(0); + +``` + +This code will compile and run. However, this "solution" contains a problem: SimpleArray does not know how to control pointers, and therefore, when the program exits, a memory leak is detected. + +``` +1 undeleted objects left +1 object of type Dummy left +24 bytes of leaked memory + +``` + +We, as the developers of SimpleArray, have a duty to close this loophole. To do this, let's add another template method to the class with an overload of the operator '<<' – this time for pointers. Since it is a template, it is also only included in the resulting source code "on demand": when the programmer tries to use this overload, that is, write a pointer to the container. Otherwise, the method is ignored. + +``` +template +class SimpleArray +{ +   ... +   template +   SimpleArray *operator<<(P *p) +   { +      data[expand()] = (T)*p; +      if(CheckPointer(p) == POINTER_DYNAMIC) delete p; +      return &this; +   } + +``` + +This specialization throws a compilation error ("object pointer expected") when instantiating a template with a pointer type. Thus, we inform the user that this mode is not supported. + +``` +   SimpleArray bad; // ERROR is generated in SimpleArray.mqh + +``` + +In addition, it performs another protective action. If the client class still has a copy constructor, then saving dynamically allocated objects in the container will no longer lead to a memory leak: a copy of the object at the passed pointer P *p remains in the container, and the original is deleted. When the container is destroyed at the end of the OnStart function, its internal array data will automatically call the destructors for its elements. + +``` +void OnStart() +{ +   ... +   SimpleArray good; +   good << new Dummy(0); +} // SimpleArray "cleans" its elements + // no forgotten objects in memory + +``` + +Method templates and "simple" methods can be defined outside of the main class block (or class template), similar to what we saw in the [Splitting Declaration and Definition of Class](/en/book/oop/classes_and_interfaces/classes_declaration_definition) section. At the same time, they are all preceded by the template header (TemplatesExtended.mq5): + +``` +template +class ClassType +{ +   ClassType() // private constructor +   { +      s = &this; +   } +   static ClassType *s; // object pointer (if it was created) +public: +   static ClassType *create() // creation (on first call only) +   { +      static ClassType single; //single pattern for every T +      return single; +   } +  +   static ClassType *check() // checking pointer without creating +   { +      return s; +   } +    +   template +   void method(const U &u); +}; +    +template +template +void ClassType::method(const U &u) +{ +   Print(__FUNCSIG__, " ", typename(T), " ", typename(U)); +} +    +template +static ClassType *ClassType::s = NULL; + +``` + +It also shows the initialization of a templated static variable, denoting the singleton design pattern. + +In the function OnStart, create an instance of the template and test it: + +``` +void OnStart() +{ +   ClassType *object = ClassType::create(); +   double d = 5.0; +   object.method(d); +   // OUTPUT: +   // void ClassType::method(const double&) string double +    +   Print(ClassType::check()); // 1048576 (an example of an instance id) +    Print(ClassType::check());   // 0 (there is no instance for T=long) +} + +``` diff --git a/skills/mql5/references/book/02-oop/0134-oop-templates-templates-nested.md b/skills/mql5/references/book/02-oop/0134-oop-templates-templates-nested.md new file mode 100644 index 0000000..14aca43 --- /dev/null +++ b/skills/mql5/references/book/02-oop/0134-oop-templates-templates-nested.md @@ -0,0 +1,65 @@ +# Nested templates + +Templates can be nested within classes/structures or within other class/structure templates. The same is true for unions. + +In the section [Unions](/en/book/oop/structs_and_unions/unions), we saw the ability to "convert" long values ​​to double and back again without loss of precision. + +Now we can use templates to write a universal "converter"(TemplatesConverter.mq5). The template class Converter has two parameters T1 and T2, indicating the types between which the conversion will be performed. To write a value according to the rules of one type and read according to the rules of another, we again need a union. We will also make it a template (DataOverlay) with parameters U1 and U2, and define it inside the class. + +The class provides a convenient transformation by overloading the operators [], in the implementation of which the union fields are written and read. + +``` +template +class Converter +{ +private: +   template +   union DataOverlay +   { +      U1 L; +      U2 D; +   }; +    +   DataOverlay data; +    +public: +   T2 operator[](const T1 L) +   { +      data.L = L; +      return data.D; +   } +    +   T1 operator[](const T2 D) +   { +      data.D = D; +      return data.L; +   } +}; + +``` + +The union is used to describe the field DataOverlaydata within the class. We could use T1 and T2 directly in DataOverlay and not make this union a template. But to demonstrate the technique itself, the parameters of the outer template are passed to the inner template when the data field is generated. Inside the DataOverlay, the same pair of types will be known as U1 and U2 (in addition to T1 and T2). + +Let's see the template in action. + +``` +#define MAX_LONG_IN_DOUBLE       9007199254740992 +    +void OnStart() +{ +   Converter c; +    +   const ulong value = MAX_LONG_IN_DOUBLE + 1; +    +   double d = value; // possible loss of data due to type conversion +   ulong result = d; // possible loss of data due to type conversion +    +   Print(value == result); // false +    +   double z = c[value]; +   ulong restored = c[z]; +    +   Print(value == restored); // true +} + +``` diff --git a/skills/mql5/references/book/02-oop/0135-oop-templates-templates-specialization.md b/skills/mql5/references/book/02-oop/0135-oop-templates-templates-specialization.md new file mode 100644 index 0000000..da0bc6c --- /dev/null +++ b/skills/mql5/references/book/02-oop/0135-oop-templates-templates-specialization.md @@ -0,0 +1,108 @@ +# Absent template specialization + +In some cases, it may be necessary to provide a template implementation for a particular type (or set of types) in a way that differs from the generic one. For example, it usually makes sense to prepare a special version of the swap function for pointers or arrays. In such cases, C++ allows you to do what is called template specialization, that is, to define a version of the template in which the generic type parameter T is replaced by the required concrete type. + +When specializing function and method templates, specific types must be specified for all parameters. This is called complete specialization. + +In the case of C++ object type templates, specialization can be not only complete but also partial: it specifies the type of only some of the parameters (and the rest will be inferred or specified when the template is instantiated). There can be several partial specializations: the only condition for this is that each specialization must describe a unique combination of types. + +Unfortunately, there is no specialization in MQL5 in the full sense of the word. + +Template function specialization is no different from overloading. For example, given the following template func: + +``` +template +void func(T t) { ... } + +``` + +it is allowed to provide its custom implementation for a given type (such as string) in one of the forms: + +``` +// explicit specialization  +template<> +void func(string t) { ... } + +``` + +or: + +``` +// normal overload  +void func(string t) { ... } + +``` + +Only one of the forms must be selected. Otherwise, we get a compilation error "'func' - function already defined and has body". + +As for the specialization of classes, inheritance from templates with an indication of specific types for some of the template parameters can be considered as an equivalent of their partial specialization. Template methods can be overridden in a derived class. + +The following example (TemplatesExtended.mq5) shows several options for using template parameters as parent types, including cases where one of them is specified as specific. + +``` +#define RTTI Print(typename(this)) +    +class Base +{ +public: +   Base() { RTTI; } +}; +    +template  +class Derived : public T +{ +public: +   Derived() { RTTI; } +};  +    +template  +class Base1 +{ +   Derived object; +public: +   Base1() { RTTI; } +};  +    +template                // complete "specialization" +class Derived1 : public Base1 // 1 of 1 parameter is set  +{ +public: +   Derived1() { RTTI; } +};  +    +template  +class Base2 : public T +{ +public: +   Base2() { RTTI; } +};  +    +template                    // partial "specialization" +class Derived2 : public Base2 // 1 of 2 parameters is set  +{ +public: +   Derived2() { RTTI; } +}; + +``` + +We will provide an instantiation of an object according to a template using a variable: + +``` +   Derived2> derived2; + +``` + +Debug type logging using the RTTI macro produces the following result: + +``` +Base +Derived +Base1 +Derived1 +Base2,string> +Derived2> + +``` + +When developing [libraries](/en/book/advanced/libraries) that come as closed binary, you must ensure that templates are explicitly instantiated for all types that future users of the library are expected to work with. You can do this by explicitly calling function templates and creating objects with type parameters in some auxiliary function, for example, bound to the initialization of a global variable. diff --git a/skills/mql5/references/book/03-common/0136-common.md b/skills/mql5/references/book/03-common/0136-common.md new file mode 100644 index 0000000..0ac0633 --- /dev/null +++ b/skills/mql5/references/book/03-common/0136-common.md @@ -0,0 +1,22 @@ +# Common MQL5 APIs + +In the previous parts of the book, we studied the basic concepts, syntax, and rules for using MQL5 language constructs. However, this is only a foundation for writing real programs that meet trader requirements, such as analytical data processing and automatic trading. Solving such tasks would not be possible without a wide range of built-in functions and means of interaction with the MetaTrader 5 terminal, which make up the MQL5 API. + +In this chapter, we will start mastering the MQL5 API and will continue to do so until the end of the book, gradually getting familiar with all the specialized subsystems. + +The list of technologies and capabilities provided to any MQL program by the kernel (the runtime environment of MQL programs inside the terminal) is very large. This is why it makes sense to start with the simplest things that can be useful in most programs. In particular, here we will look at functions specialized for work with arrays, strings, files, data transformation, user interaction, mathematical functions, and environmental control. + +Previously, we learned to describe our own [functions](/en/book/basis/functions) in MQL5 and call them. The built-in functions of the MQL5 API are available from the source code, as they say, "out of the box", i.e. without any preliminary description. + +It is important to note that, unlike in C++, no additional preprocessor directives are required to include a specific set of built-in functions in a program. The names of all MQL5 API functions are present in the global context (namespace), always and unconditionally. + +On the one hand, this is convenient, but on the other hand, it requires you to be aware of a possible name conflict. If you accidentally try to use one of the names of the built-in functions, it will override the standard implementation, which can lead to unexpected consequences: at best, you get a compiler error about ambiguous overload, and at worst, all the usual calls will be redirected to the “new” implementation, without any warnings. + +In theory, similar names can be used in other contexts, for example, as a class method name or in a dedicated (user) namespace. In such cases, calling a global function can be done using the context resolution operator: we discussed this situation in the section [Nested types, namespaces, and the '::' context operator](/en/book/oop/classes_and_interfaces/classes_namespace_context). + +``` +MQL5 Programming for Traders — Source Codes from the Book. Part 4 + +Examples from the book are also available in the public project \MQL5\Shared Projects\MQL5Book + +``` diff --git a/skills/mql5/references/book/03-common/0137-common-conversions.md b/skills/mql5/references/book/03-common/0137-common-conversions.md new file mode 100644 index 0000000..0836d21 --- /dev/null +++ b/skills/mql5/references/book/03-common/0137-common-conversions.md @@ -0,0 +1,37 @@ +# Built-in type conversions + +Programs often operate with different data types. We have already encountered mechanisms of explicit and implicit casting of built-in types in the [Types Casting](/en/book/basis/conversion) section. They provide universal conversion methods that are not always suitable, for one reason or another. The MQL5 API provides a set of conversion functions using which a programmer can manage data conversions from one type to another and configure conversion results. + +Among the most frequently used functions are those which convert various types to strings or vice versa. Specifically, this includes conversions for numbers, dates and times, colors, structures, and enums. Some types have additional specific operations. + +This section considers various data conversion methods, providing programmers with the necessary tools to work with a variety of data types in trading robots. It includes the following subsections: + +[Numbers to strings and vice versa](/en/book/common/conversions/conversions_numbers): + +- This subsection explores methods for converting numerical values to strings and vice versa. It covers important aspects such as number formatting and handling various number systems. + +[Normalization of doubles](/en/book/common/conversions/conversions_normalize): + +- Normalizing double numbers is an important aspect when working with financial data. This section discusses normalization methods, ways to avoid precision loss, and processing floating-point values. + +[Date and time](/en/book/common/conversions/conversions_datetime): + +- Conversion of date and time plays a key role in trading strategies. This subsection discusses methods for working with dates, time intervals, and special data types like datetime. + +[Color](/en/book/common/conversions/conversions_color): + +- In MQL5, colors are represented by a special data type. The subsection examines the conversion of color values, their representation and use in graphical elements of trading robots. + +[Structures](/en/book/common/conversions/conversions_structs): + +- Data conversion within structures is an important topic when dealing with complex structured data. We will see methods of interacting with structures and their elements. + +[Enumerations](/en/book/common/conversions/conversions_enums): + +- Enumerations provide named constants and enhance code readability. This subsection discusses how to convert enumeration values and effectively use them in a program. + +[Type complex](/en/book/common/conversions/conversions_complex): + +- The complex type is designed to work with complex numbers. This section considers methods for converting and using complex numbers. + +We will study all such functions in this chapter. diff --git a/skills/mql5/references/book/03-common/0138-common-conversions-conversions-numbers.md b/skills/mql5/references/book/03-common/0138-common-conversions-conversions-numbers.md new file mode 100644 index 0000000..6ba65c7 --- /dev/null +++ b/skills/mql5/references/book/03-common/0138-common-conversions-conversions-numbers.md @@ -0,0 +1,137 @@ +# Numbers to strings and vice versa + +Numbers to strings and back, strings to numbers, can be converted using the [explicit type casting](/en/book/basis/conversion/conversion_explicit) operator. For example, for types double and string, it might look like this: + +``` +double number = (double)text; +string text = (string)number; + +``` + +Strings can be converted to other numeric types, such as float, long, int, etc. + +Note that casting to a real type (float) provides fewer significant digits, which in some applications may be considered an advantage as it gives a more compact and easier-to-read representation. + +Strictly speaking, this type casting is not mandatory, since even if there is no explicit cast operator, the compiler will produce type casting implicitly. However, you will receive a compiler warning in this case, and thus it is recommended to always make type castings explicit. + +The MQL5 API provides some other useful functions, which are described below. The descriptions are followed by a general example. + +double StringToDouble(string text) + +The StringToDouble function converts a string to a double number. + +It is a complete analog of type casting to (double). Its practical purpose is actually limited to preserving backward compatibility with legacy source codes. The preferred method is type casting, as it is more compact and is implemented within the syntax of the language. + +According to the conversion process, a string should contain a sequence of characters that meet the rules for writing literals of numeric types (both [float](/en/book/basis/builtin_types/float_numbers) and [integer](/en/book/basis/builtin_types/integer_numbers)). In particular, a string may begin with a '+' or '-' sign, followed by a digit, and may continue further as a sequence of digits. + +Real numbers can contain a single dot character '.' separating the fractional part and an optional exponent in the following format: character 'e' or 'E' followed by a sequence of digits for the degree (it can also be preceded by a '+' or '-'). + +For integers, hexadecimal notation is supported, i.e., the "0x" prefix can be followed not only by decimal digits but also by 'A', 'B', 'C', 'D', 'E', 'F' (in any position). + +When any non-expected character (such as a letter, punctuation mark, second period, or intermediate space) is encountered in the string, the conversion ends. In this case, if there were allowed characters before this position, they are interpreted as a number, and if not, the result will be 0. + +Initial empty characters (spaces, tabs, newlines) are skipped and do not affect the conversion. If they are followed by numbers and other characters that meet the rules, the number will be received correctly. + +The following table provides some examples of valid conversions with explanations. + +| string | double | Result | +| --- | --- | --- | +| "123.45" | 123.45 | One decimal point | +| "\t   123" | 123.0 | Whitespace characters at the beginning are ignored | +| "-12345" | -12345.0 | A signed number | +| "123e-5" | 0.00123 | Scientific notation with exponent | +| "0x12345" | 74565.0 | Hexadecimal notation | + +The following table shows examples of incorrect conversions. + +| string | double | Result | +| --- | --- | --- | +| "x12345" | 0.0 | Starts with an unresolved character (letter) | +| "123x45" | 123.0 | The letter after 123 breaks conversion | +| "   12 3" | 12.0 | The space after 12 breaks the conversion | +| "123.4.5" | 123.4 | The second decimal point after 123.4 breaks the conversion | +| "1,234.50" | 1.0 | The comma after 1 breaks conversion | +| "-+12345" | 0.0 | Too many signs (two) | + +string DoubleToString(double number, int digits = 8) + +The DoubleToString function converts a number to a string with the specified precision (number of digits from -16 to 16). + +It does a job similar to casting a number to (string) but allows you to choose, using the second parameter, the number precision in the resulting string. + +The operator (string) applied to double, displays 16 significant digits (total, including mantissa and fractional part). The full equivalent of this cannot be achieved with a function. + +If the digits parameter is greater than or equal to 0, it indicates the number of decimal places. In this case, the number of characters before the decimal mark is determined by the number itself (how large it is), and if the total number of characters in the mantissa and that indicated in digits turns out to be greater than 16, then the least significant digits will contain "garbage" (due to how the [real numbers](/en/book/basis/builtin_types/float_numbers) are stored). 16 characters represent the average maximum precision for type double, i.e., setting digits to 16 (maximum) will only provide an accurate representation of values less than 10. + +If the digits parameter is less than 0, it specifies the number of significant digits, and this number will be output in scientific format with an exponent. In terms of precision (but not recording format), setting digits=-16 in the function generates a result close to casting (string). + +The function, as a rule, is used for uniform formatting of data sets (including right-alignment of a column of a certain table), in which values have the same decimal precision (for example, the number of decimal places in the financial instrument price or a lot size). + +Please note that errors may occur during mathematical calculations, causing the result to be not a valid number although it has the type double (or float). For example, a variable might contain the result of calculating the square root of a negative number. + +  + +Such values are called "Not a Number" (NaN) and are displayed when cast to (string) as a short hint of error type, for example, -nan(ind) (ind - undefined), nan(inf) (inf - infinity). When using the DoubleToString function, you will get a large number that makes no sense. + +  + +It is especially important that all subsequent calculations with NaN will also give NaN. To check such values, there is the [MathIsValidNumber](/en/book/common/maths/maths_nan) function. + +long StringToInteger(string text) + +The function converts a string to a number of type long. Note that the result type is definitely long, and not int (despite the name) and not ulong. + +An alternative way is to typecast using the operator (long). Moreover, any other integer type of your choice can be used for the cast:(int), (uint), (ulong), etc. + +The conversion rules are similar to the type double, but exclude the dot character and the exponent from the allowed characters. + +string IntegerToString(long number, int length = 0, ushort filling = ' ') + +Function IntegerToString converts an integer of type long to a string of the specified length. If the number representation takes less than one character, it is left-padded with a character filling (with a space by default). Otherwise, the number is displayed in its entirety, without restriction. Calling a function with default parameters is equivalent to casting to (string). + +Of course, smaller integer types (for example, int, short) will be processed by the function without problems. + +Examples of using all the above functions are given in the script ConversionNumbers.mq5. + +``` +void OnStart() +{ +   const string text = "123.4567890123456789"; +   const string message = "-123e-5 buckazoid"; +   const double number = 123.4567890123456789; +   const double exponent = 1.234567890123456789e-5; +    +   // type casting +   Print((double)text);    // 123.4567890123457 +   Print((double)message); // -0.00123 +   Print((string)number);  // 123.4567890123457 +   Print((string)exponent);// 1.234567890123457e-05 +   Print((long)text);      // 123 +   Print((long)message);   // -123 +    +   // converting with functions +   Print(StringToDouble(text)); // 123.4567890123457 +   Print(StringToDouble(message)); // -0.00123 +    +   // by default, 8 decimal digits +   Print(DoubleToString(number)); // 123.45678901 +    +   // custom precision +   Print(DoubleToString(number, 5));  // 123.45679 +   Print(DoubleToString(number, -5)); // 1.23457e+02 +   Print(DoubleToString(number, -16));// 1.2345678901234568e+02 +   Print(DoubleToString(number, 16)); // 123.4567890123456807 +   // last 2 digits are not accurate! +   Print(MathSqrt(-1.0));                 // -nan(ind) +   Print(DoubleToString(MathSqrt(-1.0))); // 9223372129088496176.54775808 +    +   Print(StringToInteger(text));      // 123 +   Print(StringToInteger(message));   // -123 +    +   Print(IntegerToString(INT_MAX));         // '2147483647' +   Print(IntegerToString(INT_MAX, 5));      // '2147483647' +   Print(IntegerToString(INT_MAX, 16));     // '      2147483647' +   Print(IntegerToString(INT_MAX, 16, '0'));// '0000002147483647' +} + +``` diff --git a/skills/mql5/references/book/03-common/0139-common-conversions-conversions-normalize.md b/skills/mql5/references/book/03-common/0139-common-conversions-conversions-normalize.md new file mode 100644 index 0000000..4e948c9 --- /dev/null +++ b/skills/mql5/references/book/03-common/0139-common-conversions-conversions-normalize.md @@ -0,0 +1,40 @@ +# Normalization of doubles + +The MQL5 API provides a function for rounding floating point numbers to a specified precision (the number of significant digits in the fractional part). + +double NormalizeDouble(double number, int digits) + +Rounding is required in trading algorithms to set volumes and prices in [orders](/en/book/automation/experts/experts_mqltraderequest). Rounding is performed according to the standard rules: the last visible digit is increased by 1 if the next (discarded) digit is greater than or equal to 5. + +Valid values of the parameter digits: 0 to 8. + +Examples of using the function are available in the ConversionNormal.mq5 file. + +``` +void OnStart() +{ +   Print(M_PI);                      // 3.141592653589793 +   Print(NormalizeDouble(M_PI, 16)); // 3.14159265359 +   Print(NormalizeDouble(M_PI, 8));  // 3.14159265 +   Print(NormalizeDouble(M_PI, 5));  // 3.14159 +   Print(NormalizeDouble(M_PI, 1));  // 3.1 +   Print(NormalizeDouble(M_PI, -1)); // 3.14159265359 +   ... + +``` + +Due to the fact that any real number has a limited [internal representation](/en/book/basis/builtin_types/float_numbers) precision, the number can be displayed approximately even when normalized: + +``` +   ... +   Print(512.06);                    // 512.0599999999999 +   Print(NormalizeDouble(512.06, 5));// 512.0599999999999 +   Print(DoubleToString(512.06, 5)); // 512.06000000 +   Print((float)512.06);             // 512.06 +} + +``` + +This is normal and inevitable. For more compact formatting, use the functions [DoubleToString](/en/book/common/conversions/conversions_numbers), [StringFormat](/en/book/common/strings/strings_format) or intermediate casting to (float). + +To round a number up or down to the nearest integer, use the functions MathRound, MathCeil, MathFloor (see section [Rounding functions](/en/book/common/maths/maths_rounding)). diff --git a/skills/mql5/references/book/03-common/0140-common-conversions-conversions-datetime.md b/skills/mql5/references/book/03-common/0140-common-conversions-conversions-datetime.md new file mode 100644 index 0000000..df3e2c0 --- /dev/null +++ b/skills/mql5/references/book/03-common/0140-common-conversions-conversions-datetime.md @@ -0,0 +1,405 @@ +# Date and Time + +Values of type datetime intended for storing [date and/or time](/en/book/basis/builtin_types/datetime) usually undergo several types of conversion: + +- into lines and back to display data to the user and to read data from external sources +- into special structures MqlDateTime (see below) to work with individual date and time components +- to the number of seconds elapsed since 01/01/1970, which corresponds to the internal representation of datetime and is equivalent to the integer type long + +For the last item, use datetime to (long) casting, or vice versa, long To (datetime), but note that the supported date range is from January 1, 1970 (value 0) to December 31, 3000 (32535215999 seconds). + +For the first two options, the MQL5 API provides the following functions. + +string TimeToString(datetime value, int mode = TIME_DATE | TIME_MINUTES) + +Function TimeToString converts a value of type datetime to a string with date and time components, according to the mode parameter in which you can set an arbitrary combination of flags: + +- TIME_DATE — date in the format "YYYY.MM.DD" +- TIME_MINUTES — time in the format "hh:mm", i.e., with hours and minutes +- TIME_SECONDS — time in "hh:mm:ss" format, i.e. with hours, minutes and seconds + +To output the date and time data in full, you can set mode equal to TIME_DATE | TIME_SECONDS (the TIME_DATE | TIME_MINUTES | TIME_SECONDS option will also work, but is redundant). This is equivalent to casting a value of type datetime to (string). + +Usage examples are provided in the ConversionTime.mq5 file. + +``` +#define PRT(A) Print(#A, "=", (A)) +  +void OnStart() +{ +   datetime time = D'2021.01.21 23:00:15'; +   PRT((string)time); +   PRT(TimeToString(time)); +   PRT(TimeToString(time, TIME_DATE | TIME_MINUTES | TIME_SECONDS)); +   PRT(TimeToString(time, TIME_MINUTES | TIME_SECONDS)); +   PRT(TimeToString(time, TIME_DATE | TIME_SECONDS)); +   PRT(TimeToString(time, TIME_DATE)); +   PRT(TimeToString(time, TIME_MINUTES)); +   PRT(TimeToString(time, TIME_SECONDS)); +} + +``` + +The script will print the following log: + +``` +(string)time=2021.01.21 23:00:15 +TimeToString(time)=2021.01.21 23:00 +TimeToString(time,TIME_DATE|TIME_MINUTES|TIME_SECONDS)=2021.01.21 23:00:15 +TimeToString(time,TIME_MINUTES|TIME_SECONDS)=23:00:15 +TimeToString(time,TIME_DATE|TIME_SECONDS)=2021.01.21 23:00:15 +TimeToString(time,TIME_DATE)=2021.01.21 +TimeToString(time,TIME_MINUTES)=23:00 +TimeToString(time,TIME_SECONDS)=23:00:15 + +``` + +datetime StringToTime(string value) + +The function StringToTime converts a string containing a date and/or time to a value of type datetime. The string can contain only the date, only the time, or the date and time together. + +The following formats are recognized for dates: + +- "YYYY.MM.DD" +- "YYYYMMDD" +- "YYYY/MM/DD" +- "YYYY-MM-DD" +- "DD.MM.YYYY" +- "DD/MM/YYYY" +- "DD-MM-YYYY" + +The following formats are supported for time: + +- "hh:mm" +- "hh:mm:ss" +- "hhmmss" + +There must be at least one space between the date and time. + +If only time is present in the string, the current date will be substituted in the result. If only the date is present in the string, the time will be set to 00:00:00. + +If the supported syntax in the string is broken, the result is the current date. + +The function usage examples are given in the script ConversionTime.mq5. + +``` +void OnStart() +{ +   string timeonly = "21:01";   // time only +   PRT(timeonly); +   PRT((datetime)timeonly); +   PRT(StringToTime(timeonly)); +    +   string date = "2000-10-10";  // date only +   PRT((datetime)date); +   PRT(StringToTime(date)); +   PRT((long)(datetime)date); +   long seconds = 60; +   PRT((datetime)seconds); // 1 minute from the beginning of 1970 +    +   string ddmmyy = "15/01/2012 01:02:03"; // date and time, and the date in +   PRT(StringToTime(ddmmyy));             // in "forward" order, still ok +    +   string wrong = "January 2-nd"; +   PRT(StringToTime(wrong)); +} + +``` + +In the log, we will see something like the following (####.##.## is the current date the script was launched): + +``` +timeonly=21:01 +(datetime)timeonly=####.##.## 21:01:00 +StringToTime(timeonly)=####.##.## 21:01:00 +(datetime)date=2000.10.10 00:00:00 +StringToTime(date)=2000.10.10 00:00:00 +(long)(datetime)date=971136000 +(datetime)seconds=1970.01.01 00:01:00 +StringToTime(ddmmyy)=2012.01.15 01:02:03 +(datetime)wrong=####.##.## 00:00:00 + +``` + +In addition to StringToTime, you can use the cast operator (datetime) to convert strings to dates and times. However, the advantage of the function is that when an incorrect source string is detected, the function sets an internal variable with an error code _LastError (which is also available via the function [GetLastError](/en/book/common/environment/env_last_error)). Depending on which part of the string contains uninterpreted data, the error code could be ERR_WRONG_STRING_DATE (5031), ERR_WRONG_STRING_TIME (5032) or another option from the list related to getting the date and time from the string. + +bool TimeToStruct(datetime value, MqlDateTime &struct) + +To parse date and time components separately, the MQL5 API provides the TimeToStruct function which converts a value of type datetime into the MqlDateTime structure: + +``` +struct MqlDateTime +{  +   int year;           // year +   int mon;            // month +   int day;            // day +   int hour;           // hour +   int min;            // minutes +   int sec;            // seconds +   int day_of_week;    // day of the week +   int day_of_year;    // the number of the day in a year (January 1 has number 0) +}; + +``` + +The days of the week are numbered in the American manner: 0 for Sunday, 1 for Monday, and so on up to 6 for Saturday. They can be identified using the built-in ENUM_DAY_OF_WEEK enumeration. + +The function returns true if successful and false on error, in particular, if an incorrect date is passed. + +Let's check the performance of the function using the ConversionTimeStruct.mq5 script. To do this, let's create the time array of type datetime with test values. We will call TimeToStruct for each of them in a loop. + +The results will be added to an array of structures MqlDateTime mdt[]. We will first initialize it with zeros, but since the built-in function [ArrayInitialize](/en/book/common/arrays/arrays_init_fill) does not know how to handle structures, we will have to write an overload for it (in the future we will learn an easier way to fill an array with zeros: in the section [Zeroing objects and arrays](/en/book/common/arrays/zero_memory) the function ZeroMemory will be introduced). + +``` +int ArrayInitialize(MqlDateTime &mdt[], MqlDateTime &init) +{ +   const int n = ArraySize(mdt); +   for(int i = 0; i < n; ++i) +   { +      mdt[i] = init; +   } +   return n; +} + +``` + +After the process, we will output the array of structures to the log using the built-in function [ArrayPrint](/en/book/common/arrays/arrays_print). This is the easiest way to provide nice data formatting (it can be used even if there is only one structure: just put it in an array of size 1). + +``` +void OnStart() +{ +   // fill the array with tests +   datetime time[] = +   { +      D'2021.01.28 23:00:15', // valid datetime value +      D'3000.12.31 23:59:59', // the largest supported date and time +      LONG_MAX // invalid date: will cause an error ERR_INVALID_DATETIME (4010) +   }; +    +   // calculate the size of the array at compile time +   const int n = sizeof(time) / sizeof(datetime); +    +   MqlDateTime null = {}; // example with zeros +   MqlDateTime mdt[]; +    +   // allocating memory for an array of structures with results +   ArrayResize(mdt, n); +    +   // call our ArrayInitialize overload  +   ArrayInitialize(mdt, null); +    +   // run tests +   for(int i = 0; i < n; ++i) +   { +      PRT(time[i]); // displaying initial data +    +      if(!TimeToStruct(time[i], mdt[i])) // if an error occurs, output its code +      { +         Print("error: ", _LastError); +         mdt[i].year = _LastError; +      } +   } +    +   // output the results to the log +   ArrayPrint(mdt); +   ... +} + +``` + +As a result, we get the following strings in the log: + +``` +time[i]=2021.01.28 23:00:15 +time[i]=3000.12.31 23:59:59 +time[i]=wrong datetime +wrong datetime -> 4010 +    [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] +[0]   2021     1    28     23     0    15             4            27 +[1]   3000    12    31     23    59    59             3           364 +[2]   4010     0     0      0     0     0             0             0 + +``` + +You can make sure that all fields have received the appropriate values. For incorrect initial dates, we store the error code in the year field (in this case, there is only one such error: 4010, ERR_INVALID_DATETIME). + +Recall that for the maximum date value in MQL5, the DATETIME_MAX constant is introduced, equal to the integer value 0x793406fff, which corresponds to 23:59:59 December 31, 3000. + +The most common problem that is solved using the function TimeToStruct, is getting the value of a particular date/time component. Therefore, it makes sense to prepare an auxiliary header file (MQL5Book/DateTime.mqh) with a ready implementation option. The file has the datetime class. + +``` +class DateTime +{ +private: +   MqlDateTime mdtstruct; +   datetime origin; +    +   DateTime() : origin(0) +   { +      TimeToStruct(0, mdtstruct); +   } +    +   void convert(const datetime &dt) +   { +      if(origin != dt) +      { +         origin = dt; +         TimeToStruct(dt, mdtstruct); +      } +   } +    +public: +   static DateTime *assign(const datetime dt) +   { +      _DateTime.convert(dt); +      return &_DateTime; +   } +   ENUM_DAY_OF_WEEK timeDayOfWeek() const +   { +      return (ENUM_DAY_OF_WEEK)mdtstruct.day_of_week; +   } +   int timeDayOfYear() const +   { +      return mdtstruct.day_of_year; +   } +   int timeYear() const +   { +      return mdtstruct.year; +   } +   int timeMonth() const +   { +      return mdtstruct.mon; +   } +   int timeDay() const +   { +      return mdtstruct.day; +   } +   int timeHour() const +   { +      return mdtstruct.hour; +   } +   int timeMinute() const +   { +      return mdtstruct.min; +   } +   int timeSeconds() const +   { +      return mdtstruct.sec; +   } +    +   static DateTime _DateTime; +}; +    +static DateTime DateTime::_DateTime; + +``` + +The class comes with several macros that make it easier to call its methods. + +``` +#define TimeDayOfWeek(T) DateTime::assign(T).timeDayOfWeek() +#define TimeDayOfYear(T) DateTime::assign(T).timeDayOfYear() +#define TimeYear(T) DateTime::assign(T).timeYear() +#define TimeMonth(T) DateTime::assign(T).timeMonth() +#define TimeDay(T) DateTime::assign(T).timeDay() +#define TimeHour(T) DateTime::assign(T).timeHour() +#define TimeMinute(T) DateTime::assign(T).timeMinute() +#define TimeSeconds(T) DateTime::assign(T).timeSeconds() +    +#define _TimeDayOfWeek DateTime::_DateTime.timeDayOfWeek +#define _TimeDayOfYear DateTime::_DateTime.timeDayOfYear +#define _TimeYear DateTime::_DateTime.timeYear +#define _TimeMonth DateTime::_DateTime.timeMonth +#define _TimeDay DateTime::_DateTime.timeDay +#define _TimeHour DateTime::_DateTime.timeHour +#define _TimeMinute DateTime::_DateTime.timeMinute +#define _TimeSeconds DateTime::_DateTime.timeSeconds + +``` + +The class has the mdtstruct field of the MqlDateTime structure type. This field is used in all internal conversions. Structure fields are read using getter methods: a corresponding method is allocated for each field. + +One static instance is defined inside the class: _DateTime (one object is enough, because all MQL programs are single-threaded). The constructor is private, so trying to create other datetime objects will fail. + +Using macros, we can conveniently receive separate components from datetime, for example, the year (TimeYear(T)), month (TimeMonth(T)), number (TimeDay(T)), or day of the week (TimeDayOfWeek(T)). + +If from one value of datetime it is necessary to receive several fields, then it is better to use similar macros in all calls except the first one without a parameter and starting with the underscore symbol: they read the desired field from the structure without re-setting the date/time and calling the TimeToStruct function. For example: + +``` +   // use the DateTime class from MQL5Book/DateTime.mqh: +   // first get the day of the week for the specified datetime value +   PRT(EnumToString(TimeDayOfWeek(time[0]))); +   // then read year, month and day for the same value +   PRT(_TimeYear()); +   PRT(_TimeMonth()); +   PRT(_TimeDay()); + +``` + +The following strings should appear in the log. + +``` +EnumToString(DateTime::_DateTime.assign(time[0]).__TimeDayOfWeek())=THURSDAY +DateTime::_DateTime.__TimeYear()=2021 +DateTime::_DateTime.__TimeMonth()=1 +DateTime::_DateTime.__TimeDay()=28 + +``` + +The built-in function EnumToString converts an element of any enumeration into a string. It will be described in a [separate section](/en/book/common/conversions/conversions_enums). + +datetime StructToTime(MqlDateTime &struct) + +The StructToTime function performs a conversion from the MqlDateTime structure (see above the description of the TimeToStruct function) containing date and time components, into a value of type datetime. The fields day_of_week and day_of_year are not used. + +If the state of the remaining fields is invalid (corresponding to a non-existent or unsupported date), the function may return either a corrected value, or WRONG_VALUE (-1 in the representation of type long), depending on the problem. Therefore, you should check for an error based on the state of the global variable [_LastError](/en/book/common/environment/env_last_error). A successful conversion is completed with code 0. Before converting, you should reset a possible failed state in _LastError (preserved as an artifact of the execution of some previous instructions) using the [ResetLastError](/en/book/common/environment/env_last_error) function. + +The StructToTime function test is also provided in the script ConversionTimeStruct.mq5. The array of structures parts is converted to datetime in the loop. + +``` +   MqlDateTime parts[] = +   { +      {0, 0, 0, 0, 0, 0, 0, 0}, +      {100, 0, 0, 0, 0, 0, 0, 0}, +      {2021, 2, 30, 0, 0, 0, 0, 0}, +      {2021, 13, -5, 0, 0, 0, 0, 0}, +      {2021, 50, 100, 0, 0, 0, 0, 0}, +      {2021, 10, 20, 15, 30, 155, 0, 0}, +      {2021, 10, 20, 15, 30, 55, 0, 0}, +   }; +   ArrayPrint(parts); +   Print(""); +    +   // convert all elements in the loop +   for(int i = 0; i < sizeof(parts) / sizeof(MqlDateTime); ++i) +   { +      ResetLastError(); +      datetime result = StructToTime(parts[i]); +      Print("[", i, "] ", (long)result, " ", result, " ", _LastError); +   } + +``` + +For each element, the resulting value and an error code are displayed. + +``` +       [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] +   [0]      0     0     0      0     0     0             0             0 +   [1]    100     0     0      0     0     0             0             0 +   [2]   2021     2    30      0     0     0             0             0 +   [3]   2021    13    -5      0     0     0             0             0 +   [4]   2021    50   100      0     0     0             0             0 +   [5]   2021    10    20     15    30   155             0             0 +   [6]   2021    10    20     15    30    55             0             0 +    +   [0] -1 wrong datetime 4010 +   [1] 946684800 2000.01.01 00:00:00 4010 +   [2] 1614643200 2021.03.02 00:00:00 0 +   [3] 1638316800 2021.12.01 00:00:00 4010 +   [4] 1640908800 2021.12.31 00:00:00 4010 +   [5] 1634743859 2021.10.20 15:30:59 4010 +   [6] 1634743855 2021.10.20 15:30:55 0 + +``` + +Note that the function corrects some values without raising the error flag. So, in element number 2, we passed the date, February 30, 2021, into the function, which was converted to March 2, 2021, and _LastError = 0. diff --git a/skills/mql5/references/book/03-common/0141-common-conversions-conversions-color.md b/skills/mql5/references/book/03-common/0141-common-conversions-conversions-color.md new file mode 100644 index 0000000..dd002e9 --- /dev/null +++ b/skills/mql5/references/book/03-common/0141-common-conversions-conversions-color.md @@ -0,0 +1,122 @@ +# Color + +The MQL5 API contains 3 built-in functions to work with the color: two of them serve for conversion of type [color](/en/book/basis/builtin_types/colors) to and from a string, and the third one provides a special color representation with transparency (ARGB). + +string ColorToString(color value, bool showName = false) + +The ColorToString function converts the passed color value to a string like "R,G,B" (where R, G, B are numbers from 0 to 255, corresponding to the intensity of the red, green, and blue component in the color) or to the color name from the list of predefined [web colors](https://www.mql5.com/ru/docs/constants/objectconstants/webcolors) if the showName parameter equals true. The color name is only returned if the color value exactly matches one of the webset. + +Examples of using the function are given in the ConversionColor.mq5 script. + +``` +void OnStart() +{ +   Print(ColorToString(clrBlue));            // 0,0,255 +   Print(ColorToString(C'0, 0, 255', true)); // clrBlue +   Print(ColorToString(C'0, 0, 250'));       // 0,0,250 +   Print(ColorToString(C'0, 0, 250', true)); // 0,0,250 (no name for this color) +   Print(ColorToString(0x34AB6821, true));   // 33,104,171 (0x21,0x68,0xAB) +} + +``` + +color StringToColor(string text) + +The StringToColor function converts a string like "R,G,B" or a string containing the name of a standard [web color](https://www.mql5.com/ru/docs/constants/objectconstants/webcolors) into a value of type [color](/en/book/basis/builtin_types/colors). If the string does not contain a properly formatted triplet of numbers or a color name, the function will return 0 (clrBlack). + +Examples can be seen in the script ConversionColor.mq5. + +``` +void OnStart() +{ +   Print(StringToColor("0,0,255")); // clrBlue +   Print(StringToColor("clrBlue")); // clrBlue +   Print(StringToColor("Blue"));    // clrBlack (no color with that name) +   // extra text will be ignored +   Print(StringToColor("255,255,255 more text"));      // clrWhite +   Print(StringToColor("This is color: 128,128,128")); // clrGray +} + +``` + +uint ColorToARGB(color value, uchar alpha = 255) + +The ColorToARGB function converts a value of type color and one-byte value alpha (specifying transparency) into an ARGB representation of a color (a value of type uint). The ARGB color format is used when creating [graphic resources](/en/book/advanced/resources/resources_resourcecreate) and [text drawing](/en/book/advanced/resources/resources_textout) on [charts](/en/book/applications/charts). + +The alpha value can vary from 0 to 255. "0" corresponds to full color transparency (when displaying a pixel of this color, it leaves the existing graph image at this point unchanged), 255 means applying full color density (when displaying a pixel of this color, it completely replaces the color of the graph at the corresponding point). The value 128 (0x80) is translucent. + +As we know the type color describes a color using three color components: red (Red), green (Green) and blue (Blue), which are stored in the format 0x00BBGGRR in a 4-byte integer (uint). Each component is a byte that specifies the saturation of that color in the range 0 to 255 (0x00 to 0xFF in hexadecimal). The highest byte is empty. For example, white color contains all colors and therefore has a meaning color equal to 0xFFFFFF. + +  + +But in certain tasks, it is required to specify the color transparency in order to describe how the image will look when superimposed on some background (on another, already existing image). For such cases, the concept of an alpha channel is introduced, which is encoded by an additional byte. + +  + +The ARGB color representation, together with the alpha channel (denoted AA), is 0xAARRGGBB. For example, the value 0x80FFFF00 means yellow (a mix of the red and green components) translucent color. + +When overlaying an image with an alpha channel on some background, the resulting color is obtained: + +``` +Cresult = (Cforeground * alpha + Cbackground * (255 - alpha)) / 255 + +``` + +where C takes the value of each of the R, G, B components, respectively. This formula is provided for reference. When using built-in functions with ARGB colors, transparency is applied automatically. + +An example of ColorToARGB application is given in ConversionColor.mq5. An auxiliary structure Argb and union ColorARGB have been added to the script for convenience when analyzing color components. + +``` +struct Argb +{ +   uchar BB; +   uchar GG; +   uchar RR; +   uchar AA; +}; +    +union ColorARGB +{ +   uint value; +   uchar channels[4]; // 0 - BB, 1 - GG, 2 - RR, 3 - AA +   Argb split[1]; +   ColorARGB(uint u) : value(u) { } +}; + +``` + +The structure is used as the split-type field in the union and provides access to the ARGB components by name. The union also has a byte array channels, which allows you to access components by index. + +``` +void OnStart() +{ +   uint u = ColorToARGB(clrBlue); +   PrintFormat("ARGB1=%X", u); // ARGB1=FF0000FF +   ColorARGB clr1(u); +   ArrayPrint(clr1.split); +   /* +       [BB] [GG] [RR] [AA] +   [0]  255    0    0  255 +   */ +    +   u = ColorToARGB(clrDeepSkyBlue, 0x40); +   PrintFormat("ARGB2=%X", u); // ARGB2=4000BFFF +   ColorARGB clr2(u); +   ArrayPrint(clr2.split); +   /* +       [BB] [GG] [RR] [AA] +   [0]  255  191    0   64 +   */ +} + +``` + +We will consider the print format function a little later, in the corresponding [section](/en/book/common/output/output_print). + +There is no built-in function to convert ARGB back to color (because it is not usually required), but those who wish to do so, can use the following macro: + +``` +#define ARGBToColor(U) (color) \ +   ((((U) & 0xFF) << 16) | ((U) & 0xFF00) | (((U) >> 16) & 0xFF)) + +``` diff --git a/skills/mql5/references/book/03-common/0142-common-conversions-conversions-structs.md b/skills/mql5/references/book/03-common/0142-common-conversions-conversions-structs.md new file mode 100644 index 0000000..b08d3d6 --- /dev/null +++ b/skills/mql5/references/book/03-common/0142-common-conversions-conversions-structs.md @@ -0,0 +1,91 @@ +# Structures + +When integrating MQL programs with external systems, in particular, when sending or receiving data via the Internet, it becomes necessary to convert data structures into byte arrays. For these purposes, the MQL5 API provides two functions: StructToCharArray and CharArrayToStruct. + +In both cases, it is assumed that a structure contains only simple [built-in types](/en/book/basis/builtin_types), that is, all built-in types except [lines](/en/book/basis/builtin_types/strings) and dynamic [arrays](/en/book/basis/arrays/arrays_overview). A structure can also contain other simple structures. Class objects and pointers are not allowed. Such structures are also called POD (Plain Old Data). + +bool StructToCharArray(const void &object, uchar &array[], uint pos = 0) + +The StructToCharArray function copies the POD structure object into the array array of type uchar. Optionally, using the parameter pos you can specify the position in the array, starting from which the bytes will be placed. By default, copying goes to the beginning of the array, and the dynamic array will be automatically increased in size if its current size is not enough for the entire structure. + +The function returns a success indicator (true) or errors (false). + +Let's check its performance with the script ConversionStruct.mq5. Let's create a new structure type DateTimeMsc, which includes the standard structure MqlDateTime (field mdt) and an additional field msc of type int to store milliseconds. + +``` +struct DateTimeMsc +{ +   MqlDateTime mdt; +   int msc; +   DateTimeMsc(MqlDateTime &init, int m = 0) : msc(m) +   { +      mdt = init; +   } +}; + +``` + +Inside the OnStart function, let's convert a test value datetime to our structure, and then to the byte array. + +``` +MqlDateTime TimeToStructInplace(datetime dt) +{ +   static MqlDateTime m; +   if(!TimeToStruct(dt, m)) +   { +      // the error code, _LastError, can be displayed +      // but here we just return zero time +      static MqlDateTime z = {}; +      return z; +   } +   return m; +} +  +#define MDT(T) TimeToStructInplace(T) +  +void OnStart() +{ +   DateTimeMsc test(MDT(D'2021.01.01 10:10:15'), 123); +   uchar a[]; +   Print(StructToCharArray(test, a)); +   Print(ArraySize(a)); +   ArrayPrint(a); +} + +``` + +We will get the following result in the log (the array is reformatted with additional line breaks to emphasize the correspondence of bytes to each of the fields): + +``` +   true +   36 +   229   7   0   0 +     1   0   0   0 +     1   0   0   0 +    10   0   0   0 +    10   0   0   0 +    15   0   0   0 +     5   0   0   0 +     0   0   0   0 +   123   0   0   0 + +``` + +bool CharArrayToStruct(void &object, const uchar &array[], uint pos = 0) + +The CharArrayToStruct function copies the array array of the uchar type to the POD structure object. Using the pos parameter, you can specify the position in the array from which to start reading bytes. + +The function returns a success indicator (true) or errors (false). + +Continuing the same example (ConversionStruct.mq5), we can restore the original date and time from the byte array. + +``` +void OnStart() +{ +   ... +   DateTimeMsc receiver; +   Print(CharArrayToStruct(receiver, a));                 // true +   Print(StructToTime(receiver.mdt), "'", receiver.msc);  // 2021.01.01 10:10:15'123 +} + +``` diff --git a/skills/mql5/references/book/03-common/0143-common-conversions-conversions-enums.md b/skills/mql5/references/book/03-common/0143-common-conversions-conversions-enums.md new file mode 100644 index 0000000..54d777d --- /dev/null +++ b/skills/mql5/references/book/03-common/0143-common-conversions-conversions-enums.md @@ -0,0 +1,86 @@ +# Enumerations + +In MQL5 API, an enumeration value can be converted to a string using the EnumToString function. There is no ready-made inverse transformation. + +string EnumToString(enum value) + +The function converts the value (i.e., the ID of the passed element) of an enumeration of any type to a string. + +Let's use it to solve one of the most popular tasks: to find out the size of the enumeration (how many elements it contains) and exactly what values correspond to all elements. For this purpose, in the header file EnumToArray.mqh we implement the special [template function](/en/book/oop/templates/templates_functions) (due to the template type E, it will work for any enum): + +``` +template +int EnumToArray(E dummy, int &values[], +   const int start = INT_MIN,  +   const int stop = INT_MAX) +{ +   const static string t = "::"; +    +   ArrayResize(values, 0); +   int count = 0; +    +   for(int i = start; i < stop && !IsStopped(); i++) +   { +      E e = (E)i; +      if(StringFind(EnumToString(e), t) == -1) +      { +         ArrayResize(values, count + 1); +         values[count++] = i; +      } +   } +   return count; +} + +``` + +The concept of its operation is based on the following. Since enumerations in MQL5 are stored as integers of type int, an implicit casting of any enumeration to (int) is supported, and an explicit casting int back to any enum type is also allowed. In this case, if the value corresponds to one of the elements of the enumeration, the EnumToString function returns a string with the ID of this element. Otherwise, the function returns a string of the form ENUM_TYPE::value. + +Thus, by looping over integers in the acceptable range and explicitly casting them to an enum type, one can then analyze the output string EnumToString for the presence of '::' to determine whether the given integer is an enum member or not. + +The StringFind function used here will be presented in the [next chapter](/en/book/common/strings), just like other string functions. + +Let's create the ConversionEnum.mq5 script to test the concept. In it, we implement an auxiliary function process, which will call the EnumToArray template, report the number of elements in the enum, and print the resulting array with matches between the enum elements and their values. + +``` +template +void process(E a) +{ +  int result[]; +  int n = EnumToArray(a, result, 0, USHORT_MAX); +  Print(typename(E), " Count=", n); +  for(int i = 0; i < n; i++) +  { +    Print(i, " ", EnumToString((E)result[i]), "=", result[i]); +  } +} + +``` + +As an enumeration for research purposes, we will use the built-in enumeration with the ENUM_APPLIED_PRICE price types. Inside the function OnStart, let's first make sure that EnumToString produces strings as described above. So, for the element PRICE_CLOSE, the function will return the string "PRICE_CLOSE", and for the value (ENUM_APPLIED_PRICE)10, which is obviously out of range, it will return "ENUM_APPLIED_PRICE::10". + +``` +void OnStart() +{ +   PRT(EnumToString(PRICE_CLOSE));            // PRICE_CLOSE +   PRT(EnumToString((ENUM_APPLIED_PRICE)10)); // ENUM_APPLIED_PRICE::10 +    +   process((ENUM_APPLIED_PRICE)0); +} + +``` + +Next, we call the function process for any value cast to ENUM_APPLIED_PRICE (or a variable of that type) and get the following result: + +``` +ENUM_APPLIED_PRICE Count=7 +0 PRICE_CLOSE=1 +1 PRICE_OPEN=2 +2 PRICE_HIGH=3 +3 PRICE_LOW=4 +4 PRICE_MEDIAN=5 +5 PRICE_TYPICAL=6 +6 PRICE_WEIGHTED=7 + +``` + +Here we see that 7 elements are defined in the enumeration, and the numbering does not start from 0, as usual, but from 1 (PRICE_CLOSE). Knowing the values associated with the elements allows in some cases to optimize the writing of algorithms. diff --git a/skills/mql5/references/book/03-common/0144-common-conversions-conversions-complex.md b/skills/mql5/references/book/03-common/0144-common-conversions-conversions-complex.md new file mode 100644 index 0000000..060e7fa --- /dev/null +++ b/skills/mql5/references/book/03-common/0144-common-conversions-conversions-complex.md @@ -0,0 +1,74 @@ +# Type complex + +The built-in type complex is a structure with two fields of type [double](/en/book/basis/builtin_types/float_numbers): + +``` +struct complex  +{  +   double      real;   // real part  +   double      imag;   // imaginary part  +}; + +``` + +This structure is described in the type conversion section because it "converts" two double numbers into a new entity, in something similar to how [structures are turned into byte arrays, and vice versa](/en/book/common/conversions/conversions_structs). Moreover, it would be rather difficult to introduce this type without describing the structures first. + +The complex structure does not have a constructor, so complex numbers must be created using an initialization list. + +``` +complex c = {re, im}; + +``` + +For complex numbers, only simple arithmetic and comparison operations are currently available: =, +, -, *, /, +=, -=, *=, /=, ==, !=. Support for [mathematical functions](/en/book/common/maths) will be added later. + +Attention! Complex variables cannot be declared as inputs (using the keyword input) for an MQL program. + +The suffix 'i' is used to describe complex (imaginary parts) constants, for example: + +``` +const complex x = 1 - 2i; +const complex y = 0.5i; + +``` + +In the following example (script Complex.mq5) a complex number is created and squared. + +``` +input double r = 1; +input double i = 2; +    +complex c = {r, i}; +    +complex mirror(const complex z) +{ +   complex result = {z.imag, z.real}; // swap real and imaginary parts +   return result; +} +    +complex square(const complex z)  +{  +   return (z * z); +}    +    +void OnStart() +{ +   Print(c); +   Print(square(c)); +   Print(square(mirror(c))); +} + +``` + +With default parameters, the script will output the following: + +``` +c=(1,2) / ok +square(c)=(-3,4) / ok +square(mirror(c))=(3,4) / ok + +``` + +Here, the pairs of numbers in parentheses are the string representation of the complex number. + +Type complex can be passed by value as a parameter of MQL functions (unlike ordinary structures, which are passed only by reference). For functions imported from [DLL](/en/book/advanced/libraries/libraries_dll), the type complex should only be passed by reference. diff --git a/skills/mql5/references/book/03-common/0145-common-strings.md b/skills/mql5/references/book/03-common/0145-common-strings.md new file mode 100644 index 0000000..7604118 --- /dev/null +++ b/skills/mql5/references/book/03-common/0145-common-strings.md @@ -0,0 +1,7 @@ +# Working with strings and symbols + +Although computers take their name from the verb "compute", they are equally successful in processing not only numbers but also any unstructured information, the most famous example of which is text. In MQL programs, text is also used everywhere, from the names of the programs themselves to comments in trade orders. To work with the text in MQL5, there is a built-in [string type](/en/book/basis/builtin_types/strings), which allows you to operate on character sequences of arbitrary length. + +To perform typical actions with strings, the MQL5 API provides a wide range of functions that can be conditionally divided into groups according to their purpose, such as string initialization, their addition, searching and replacing fragments within strings, converting strings to character arrays, accessing individual characters, as well as formatting. + +Most of the functions in this chapter return an indication of the execution status: success or error. For functions with result type bool, true is usually a success, and false is an error. For functions with result type int a value of 0 or -1 can be considered an error: this is stated in the description of each function. In all these cases, the developer can find out the essence of the problem. To do this, call the [GetLastError](/en/book/common/environment/env_last_error) function and get the specific error code: a list of all codes with explanations is available in the documentation. It's important to call GetLastError immediately after receiving the error flag because calling each following instruction in the algorithm can lead to another error. diff --git a/skills/mql5/references/book/03-common/0146-common-strings-strings-init.md b/skills/mql5/references/book/03-common/0146-common-strings-strings-init.md new file mode 100644 index 0000000..ed7b825 --- /dev/null +++ b/skills/mql5/references/book/03-common/0146-common-strings-strings-init.md @@ -0,0 +1,172 @@ +# Initialization and measurement of strings + +As we know from the [String type](/en/book/basis/builtin_types/strings) section, it is enough to describe in the code a variable of type string, and it will be ready to go. + +For any variable of string type 12 bytes are allocated for the service structure which is the internal representation of the string. The structure contains the memory address (pointer) where the text is stored, along with some other meta-information. The text itself also requires sufficient memory, but this buffer is allocated with some less obvious optimizations. + +In particular, we can describe a string along with explicit initialization, including an empty literal: + +``` +string s = ""; // pointer to the literal containing '\0' + +``` + +In that case, the pointer will be set directly to the literal, and no memory is allocated for the buffer (even if the literal is long). Obviously, static memory has already been allocated for the literal, and it can be used directly. The memory for the buffer will be allocated only if any instruction in the program changes the contents of the line. For example (note the addition operation '+' is allowed for strings): + +``` +int n = 1; +s += (string)n;    // pointer to memory containing "1"'\0'[plus reserve] + +``` + +From this point on, the string actually contains the text "1" and, strictly speaking, requires memory for two characters: the digit "1" and the implicit terminal zero '\0' (terminator of the string). However, the system will allocate a larger buffer, with some space reserved. + +When we declare a variable without an initial value, it is still implicitly initialized by the compiler, though in this case with a special NULL value: + +``` +string z; // memory for the pointer is not allocated, pointer = NULL + +``` + +Such a string requires only 12 bytes per structure, and the pointer doesn't point anywhere: that's what NULL stands for. + +In future versions of the MQL5 compiler, this behavior may change, and a small area of memory will always be initially allocated for an empty string, providing some reserved space. + +In addition to these internal features, variables of the string type are no different from variables of other types. However, due to the fact that strings can be variable in length and, more importantly, they can change their length during the algorithm, this can adversely affect the efficiency of memory allocation and performance. + +For example, if at some point the program needs to add a new word to a string, it may turn out that there is not enough memory allocated for the string. Then the MQL program execution environment, imperceptible to the user, will find a new free memory block of increased size and copy the old value there along with the added word. After that, the old address is replaced by a new one in the line's service structure. + +If there are many such operations, slowdown due to copying can become noticeable, and in addition, program memory is subject to fragmentation: old small memory areas released after copying form voids that are not suitable in size for large strings, and therefore lead to waste of memory. Of course, the terminal is able to control such situations and reorganize the memory, but this also comes at a cost. + +The most effective way to solve this problem is to explicitly indicate in advance the size of the buffer for the string and initialize it using the built-in MQL5 API functions, which we will consider later in this section. + +The basis for this optimization is just that the size of the allocated memory may exceed the current (and, potentially, the future) length of the string, which is determined by the first null character in the text. Thus, we can allocate a buffer for 100 characters, but from the start put '\0' at the very beginning, which will give a zero-length string (""). + +Naturally, it is assumed that in such cases the programmer can roughly calculate in advance the expected length of the string or its growth rate. + +Since strings in MQL5 are based on double-byte characters (which ensures Unicode support), the size of the string and buffer in characters should be multiplied by 2 to get the amount of occupied and allocated memory in bytes. + +A general example of using all functions (StringInit.mq5) will be given at the end of the section. + +bool StringInit(string &variable, int capacity = 0, ushort character = 0) + +The StringInit function is used to initialize (allocate and fill memory) and deinitialize (free memory) strings. The variable to be processed is passed in the first parameter. + +If the capacity parameter is greater than 0, then a buffer (memory area) of the specified size is allocated for the string and is filled with the symbol character. If the character is 0, then the length of the string will be zero, because the first character is terminal. + +If the capacity parameter is 0, then previously allocated memory is freed. The state of the variable becomes identical to how it was if just declared without initialization (the pointer to the buffer is NULL). More simply, the same can be done by setting the string variable to NULL. + +The function returns a success indicator (true) or errors (false). + +bool StringReserve(string &variable, uint capacity) + +The StringReserve function increases or decreases the buffer size of the string variable, at least up to the number of characters specified in the capacity parameter. If the capacity value is less than the current string length, the function does nothing. In fact, the buffer size may be larger than requested: the environment does this for reasons of efficiency in future manipulations with the string. Thus, if the function is called with a reduced value for the buffer, it can ignore the request and still return true ("no errors"). + +The current buffer size can be obtained using the function StringBufferLen (see below). + +On success, the function returns true, otherwise – false. + +Unlike StringInit the StringReserve function does not change the contents of the string and does not fill it with characters. + +bool StringFill(string &variable, ushort character) + +The StringFill function fills the specified variable string with the character character for its entire current length (up to the first zero). If a buffer is allocated for a string, the modification is done in-place, without intermediate newline and copy operations. + +The function returns a success indicator (true) or errors (false). + +int StringBufferLen(const string &variable) + +The function returns the size of the buffer allocated for the variable string. + +Note that for a literal-initialized string, no buffer is initially allocated because the pointer points to the literal. Therefore, the function will return 0 even though the length of the StringLen string (see below) may be more. + +The value -1 means that the line belongs to the client terminal and cannot be changed. + +bool StringSetLength(string &variable, uint length) + +The function sets the specified length in characters length for the variable string. The value of the length must not be greater than the current length of the string. In other words, the function only allows you to shorten the string, but not lengthen it. The length of the string is increased automatically when the [StringAdd](/en/book/common/strings/strings_concatenation) function is called, or the addition operation '+' is performed. + +The equivalent of the function StringSetLength is the call StringSetCharacter(variable, length, 0) (see section [Working with symbols and code pages](/en/book/common/strings/strings_codepages)). + +If a buffer has already been allocated for the string before the function call, the function does not change it. If the string did not have a buffer (it was pointing to a literal), decreasing the length results in allocating a new buffer and copying the shortened string into it. + +The function returns true or false in case of success or failure, respectively. + +int StringLen(const string text) + +The function returns the number of characters in the string text. Terminal zero is not taken into account. + +Please note that the parameter is passed by value, so you can calculate the length of strings not only in variables but also for any other intermediate values: calculation results or literals. + +The StringInit.mq5 script has been created to demonstrate the above functions. It uses a special version of the PRT macro, PRTE, which parses the result of an expression into true or false, and in the case of the latter additionally outputs an error code: + +``` +#define PRTE(A) Print(#A, "=", (A) ? "true" : "false:" + (string)GetLastError()) + +``` + +For debug output to the log of a string and its current metrics (line length and buffer size), the StrOut function is implemented: + +``` +void StrOut(const string &s) +{ +   Print("'", s, "' [", StringLen(s), "] ", StringBufferLen(s)); +} + +``` + +It uses the built-in StringLen and StringBufferLen functions. + +The test script performs a series of actions on a string in OnStart: + +``` +void OnStart() +{ +   string s = "message"; +   StrOut(s); +   PRTE(StringReserve(s, 100)); // ok, but we get a buffer larger than requested: 260 +   StrOut(s); +   PRTE(StringReserve(s, 500)); // ok, buffer is increased to 500 +   StrOut(s); +   PRTE(StringSetLength(s, 4)); // ok: string is shortened +   StrOut(s); +   s += "age"; +   PRTE(StringReserve(s, 100)); // ok: buffer remains at 500 +   StrOut(s); +   PRTE(StringSetLength(s, 8)); // no: string lengthening is not supported +   StrOut(s);                   //     via StringSetLength +   PRTE(StringInit(s, 8, '$')); // ok: line increased by padding +   StrOut(s);                   //     buffer remains the same +   PRTE(StringFill(s, 0));      // ok: string collapsed to empty because +   StrOut(s);                   //     was filled with 0s, the buffer is the same +   PRTE(StringInit(s, 0));      // ok: line is zeroed, including buffer +                                // we could just write s = NULL; +   StrOut(s); +} + +``` + +The script will log the following messages: + +``` +'message' [7] 0 +StringReserve(s,100)=true +'message' [7] 260 +StringReserve(s,500)=true +'message' [7] 500 +StringSetLength(s,4)=true +'mess' [4] 500 +StringReserve(s,10)=true +'message' [7] 500 +StringSetLength(s,8)=false:5035 +'message' [7] 500 +StringInit(s,8,'$')=true +'$$$$$$$$' [8] 500 +StringFill(s,0)=true +'' [0] 500 +StringInit(s,0)=true +'' [0] 0 + +``` + +Please note that the call StringSetLength with increased string length ended with error 5035 (ERR_STRING_SMALL_LEN). diff --git a/skills/mql5/references/book/03-common/0147-common-strings-strings-concatenation.md b/skills/mql5/references/book/03-common/0147-common-strings-strings-concatenation.md new file mode 100644 index 0000000..c622593 --- /dev/null +++ b/skills/mql5/references/book/03-common/0147-common-strings-strings-concatenation.md @@ -0,0 +1,67 @@ +# String concatenation + +Concatenation of strings is probably the most common string operation. In MQL5, it can be done using the '+' or '+=' operators. The first operator concatenates two strings (the operands to the left and right of the '+') and creates a temporary concatenated string that can be assigned to a target variable or passed to another part of an expression (such as a function call). The second operator appends the string to the right of the operator '+=' to the string (variable) to the left of this operator. + +In addition to this, the MQL5 API provides a couple of functions for composing strings from other strings or elements of other types. + +Examples of using functions are given in the script StringAdd.mq5, which is considered after their description. + +bool StringAdd(string &variable, const string addition) + +The function appends the specified addition string to the end of a string variable variable. Whenever possible, the system uses the available buffer of the string variable (if its size is enough for the combined result) without re-allocating memory or copying strings. + +The function is equivalent to the operator variable += addition. Time costs and memory consumption are about the same. + +The function returns true in case of success and false in case of error. + +int StringConcatenate(string &variable, void argument1, void argument2 [, void argumentI...]) + +The function converts two or more arguments of [built-in types](/en/book/basis/builtin_types) to a string representation and concatenates them in the variable string. The arguments are passed starting from the second parameter of the function. Arrays, structures, objects, pointers are not supported as arguments. + +The number of arguments must be between 2 and 63. + +String arguments are added to the resulting variable as is. + +Arguments of type double are converted with maximum precision (up to 16 significant digits), and scientific notation with exponent can be chosen if it turns out to be more compact. Arguments of type float are displayed with 5 characters. + +Values of type datetime are converted to a string with all date and time fields ("YYYY.MM.DD hh:mm:ss"). + +Enumerations, single-byte and double-byte characters are output as integers. + +Values of type color are displayed as a trio of "R,G,B" components or a color name (if available in the list of standard web colors). + +When converting type bool the strings "true" or "false" are used. + +The function StringConcatenate returns the length of the resulting string. + +StringConcatenate is designed to build a string from other sources (variables, expressions) other than the receiving variable. It is not recommended to use StringConcatenate to concatenate new chunks of data to the same row by calling StringConcatenate(variable, variable, ...). This function call is not optimized and is extremely slow compared to the operator '+' and StringAdd. + +Functions StringAdd and StringConcatenate are tested in the StringAdd.mq5 script, which uses the PRTE macro and the helper function StrOut from the [previous section](/en/book/common/strings/strings_init). + +``` +void OnStart() +{ +   string s = "message"; +   StrOut(s); +   PRTE(StringAdd(s, "r")); +   StrOut(s); +   PRTE(StringConcatenate(s, M_PI * 100, " ", clrBlue, PRICE_CLOSE)); +   StrOut(s); +} + +``` + +As a result of its execution, the following lines are displayed in the log: + +``` +'message' [7] 0 +StringAdd(s,r)=true +'messager' [8] 260 +StringConcatenate(s,M_PI*100, ,clrBlue,PRICE_CLOSE)=true +'314.1592653589793 clrBlue1' [26] 260 + +``` + +The script also includes the header file StringBenchmark.mqh with the class benchmark. It provides a framework for derived classes implemented in the script to measure the performance of various string addition methods. In particular, they make sure that adding strings using the operator '+' and the function StringAdd are comparable. This material is left for independent study. + +Additionally, the book comes with the script StringReserve.mq5: it makes a visual comparison of the speed of adding strings depending on the use or non-use of the buffer (StringReserve). diff --git a/skills/mql5/references/book/03-common/0148-common-strings-strings-comparison.md b/skills/mql5/references/book/03-common/0148-common-strings-strings-comparison.md new file mode 100644 index 0000000..8c92193 --- /dev/null +++ b/skills/mql5/references/book/03-common/0148-common-strings-strings-comparison.md @@ -0,0 +1,213 @@ +# String comparison + +To compare strings in MQL5, you can use the standard [comparison operators](/en/book/basis/expressions/operators_relational), in particular '==', '!=', '>', '<'. All such operators conduct comparisons in a character-by-character, case-sensitive manner. + +Each character has a Unicode code which is an integer of type ushort. Accordingly, first the codes of the first characters of two strings are compared, then the codes of the second ones, and so on until the first mismatch or the end of one of the strings is reached. + +For example, the string "ABC" is less than "abc", because the codes of uppercase letters in the character table are lower than the codes of the corresponding lowercase letters (on the first character we already get that "A" < "a"). If strings have matching characters at the beginning, but one of them is longer than the other, then the longer string is considered to be greater ("ABCD" > "ABC"). + +Such string relationships form the lexicographic order. When the string "A" is less than the string "B" ("A" < "B"), "A" is said to precede "B". + +To get familiar with the character codes, you can use the standard Windows application "Character Table". In it, the characters are arranged in order of increasing codes. In addition to the general Unicode table, which includes many national languages, there are code pages: ANSI standard tables with single-byte character codes — they differ for each language or group of languages. We will explore this issue in more detail in the section [Working with symbols and code pages](/en/book/common/strings/strings_codepages). + +The initial part of the character tables with codes from 0 to 127 is the same for all languages. This part is shown in the following table. + +![ASCII character code table](pics/ascii-small.png) + +ASCII character code table + +To obtain the character code, take the hexadecimal digit on the left (the line number in which the character is located) and add the number on top (the column number in which the character is located): the result is a hexadecimal number. For example, for '!' there is 2 on the left and 1 on the top, which means the character code is 0x21, or 33 in decimal. + +Codes up to 32 are control codes. Among them, you can find, in particular, tabulation (code 0x9), line feed (code 0xA), and carriage return (code 0xD). + +A pair of characters 0xD 0xA following one another is used in Windows text files to break to a new line. We got acquainted with the corresponding MQL5 literals in the [Character types](/en/book/basis/builtin_types/characters) section: 0xA can be denoted as '\n' and 0xD as '\r'. The tabulation 0x9 also has its own representation: '\t'. + +The MQL5 API provides the StringCompare function, which allows you to disable case sensitivity when comparing strings. + +int StringCompare(const string &string1, const string &string2, const bool case_sensitive = true) + +The function compares two strings and returns one of three values: +1 if the first string is "greater than" the second; 0 if strings are "equal"; -1 if the first string is "less than" the second one. The concepts of "greater than", "less than" and "equal to" depend on the case_sensitive parameter. + +When the case_sensitive parameter equals true (which is the default), the comparison is case-sensitive, with uppercase letters being considered greater than similar lowercase ones. This is the reverse of the standard lexicographic order according to character codes. + +When case-sensitive, the StringCompare function uses an order of uppercase and lowercase letters that is different from the lexicographical order. For example, we know that the relation "A" < "a" is true, in which the operator '<' is guided by character codes. Therefore, capitalized words should appear in the hypothetical dictionary (array) before words with the same lowercase letter. However, when comparing "A" and "a" using the StringCompare("A", "a") function, we get +1 which means "A" is greater than "a". Thus, in the sorted dictionary, words starting with lowercase letters will come first, and only after them will come words with capital letters. + +In other words, the function ranks the strings alphabetically. Besides that, in the case sensitivity mode, an additional rule applies: if there are strings that differ only in case, those that have uppercase letters follow their counterparts with lowercase letters (at the same positions in the word). + +If the case_sensitive parameter equals false, the letters are case insensitive, so the strings "A" and "a" are considered equal, and the function returns 0. + +You can check different comparison results by the StringCompare function and by the operator using the StringCompare.mq5 script. + +``` +void OnStart() +{ +   PRT(StringCompare("A", "a"));        // 1, which means "A" > "a" (!) +   PRT(StringCompare("A", "a", false)); // 0, which means "A" == "a" +   PRT("A" > "a");                      // false,   "A" < "a" +    +   PRT(StringCompare("x", "y"));        // -1, which means "x" < "y" +   PRT("x" > "y");                      // false,    "x" < "y" +   ... +} + +``` + +In the [Function Templates](/en/book/oop/templates/templates_functions) section, we have created a templated quicksort algorithm. Let's transform it into a template class and use it for several sorting options: using comparison operators, as well as using the StringCompare function both with and without case sensitivity enabled. Let's put the new QuickSortT class in the QuickSortT.mqh header file and connect it to the test script StringCompare.mq5. + +The sorting API has remained almost unchanged. + +``` +template +class QuickSortT +{ +public: +   void Swap(T &array[], const int i, const int j) +   { +      ... +   } +    +   virtual int Compare(T &a, T &b) +   { +      return a > b ? +1 : (a < b ? -1 : 0); +   } +    +   void QuickSort(T &array[], const int start = 0, int end = INT_MAX) +   { +      ... +         for(int i = start; i <= end; i++) +         { +            //if(!(array[i] > array[end])) +            if(Compare(array[i], array[end]) <= 0) +            { +               Swap(array, i, pivot++); +            } +         } +      ... +   } +}; + +``` + +The main difference is that we have added a virtual method Compare, which by default contains a comparison using the '>' and '<' operators, and returns +1, -1, or 0 in the same way as StringCompare. The Compare method is now used in the QuickSort method instead of a simple comparison and must be overridden in child classes in order to use the StringCompare function or any other way of comparison. + +In particular, in the StringCompare.mq5 file, we implement the following "comparator" class derived from QuickSortT: + +``` +class SortingStringCompare : public QuickSortT +{ +   const bool caseEnabled; +public: +   SortingStringCompare(const bool sensitivity = true) : +      caseEnabled(sensitivity) { } +       +   virtual int Compare(string &a, string &b) override +   { +      return StringCompare(a, b, caseEnabled); +   } +}; + +``` + +The constructor receives 1 parameter, which specifies string comparison sign taking into account (true) or ignoring (false) the register. The string comparison itself is done in the redefined virtual method Compare which calls the function StringCompare with the given arguments and setting. + +To test sorting, we need a set of strings that combines uppercase and lowercase letters. We can generate it ourselves: it is enough to develop a class that performs permutations (with repetition) of characters from a predefined set (alphabet) for a given set length (string). For example, you can limit yourself to the small alphabet "abcABC", that is, three fist English letters in both cases, and generate all possible strings of 2 characters from them. + +The class PermutationGenerator is supplied in the file PermutationGenerator.mqh and left for independent study. Here we present only its public interface. + +``` +class PermutationGenerator +{ +public: +   struct Result +   { +      int indices[]; // indexes of elements in each position of the set, i.e. +   };                // for example, the numbers of the letters of the "alphabet" in each position of the string  +   PermutationGenerator(const int length, const int elements); +   SimpleArray *run(); +}; + +``` + +When creating a generator object, you must specify the length of the generated sets length (in our case, this will be the length of the strings, i.e., 2) and the number of different elements from which the sets will be composed (in our case, this is the number of unique letters, that is, 6). With such input data, 6 * 6 = 36 variants of lines should be obtained. + +The process itself is carried out by run method. A template class is used to return an array with results SimpleArray, which we discussed in the [Method Templates](/en/book/oop/templates/templates_methods) section. In this case, it is parameterized by the structure type result. + +The call of the generator and the actual creation of strings in accordance with the array of permutations received from it (in the form of letter indices at each position for all possible strings) is performed in the auxiliary function GenerateStringList. + +``` +void GenerateStringList(const string symbols, const int len, string &result[]) +{ +   const int n = StringLen(symbols); // alphabet length, unique characters +   PermutationGenerator g(len, n); +   SimpleArray *r = g.run(); +   ArrayResize(result, r.size()); +   // loop through all received character permutations +   for(int i = 0; i < r.size(); ++i) +   { +      string element; +      // loop through all characters in the string +      for(int j = 0; j < len; ++j) +      { +         // add a letter from the alphabet (by its index) to the string +         element += ShortToString(symbols[r[i].indices[j]]); +      } +      result[i] = element; +   } +} + +``` + +Here we use several functions that are still unfamiliar to us (ArrayResize, ShortToString), but we'll get to them soon. For now, we should only know that the ShortToString function returns a string consisting of that single character based on the ushort type character code. Using the operator '+=', we concatenate each resulting string from such single-character strings. Recall that the operator [] is defined for strings, so the expression symbols[k] will return the k-th character of the symbols string. Of course, k can in turn be an integer expression, and here r[i].indices[j]  is referring to i-th element of the r array from which the index of the "alphabet" character is read for the j-th position of the string. + +Each received string is stored in an array-parameter result. + +Let's apply this information in the OnStart function. + +``` +void OnStart() +{ +   ... +   string messages[]; +   GenerateStringList("abcABC", 2, messages); +   Print("Original data[", ArraySize(messages), "]:"); +   ArrayPrint(messages); +    +   Print("Default case-sensitive sorting:"); +   QuickSortT sorting; +   sorting.QuickSort(messages); +   ArrayPrint(messages); +    +   Print("StringCompare case-insensitive sorting:"); +   SortingStringCompare caseOff(false); +   caseOff.QuickSort(messages); +   ArrayPrint(messages); +    +   Print("StringCompare case-sensitive sorting:"); +   SortingStringCompare caseOn(true); +   caseOn.QuickSort(messages); +   ArrayPrint(messages); +} + +``` + +The script first gets all string options into the messages array and then sorts it in 3 modes: using the built-in comparison operators, using the StringCompare function in the case-insensitive mode and using the same function in the case-sensitive mode. + +We will get the following log output: + +``` +Original data[36]: +[ 0] "aa" "ab" "ac" "aA" "aB" "aC" "ba" "bb" "bc" "bA" "bB" "bC" "ca" "cb" "cc" "cA" "cB" "cC" +[18] "Aa" "Ab" "Ac" "AA" "AB" "AC" "Ba" "Bb" "Bc" "BA" "BB" "BC" "Ca" "Cb" "Cc" "CA" "CB" "CC" +Default case-sensitive sorting: +[ 0] "AA" "AB" "AC" "Aa" "Ab" "Ac" "BA" "BB" "BC" "Ba" "Bb" "Bc" "CA" "CB" "CC" "Ca" "Cb" "Cc" +[18] "aA" "aB" "aC" "aa" "ab" "ac" "bA" "bB" "bC" "ba" "bb" "bc" "cA" "cB" "cC" "ca" "cb" "cc" +StringCompare case-insensitive sorting: +[ 0] "AA" "Aa" "aA" "aa" "AB" "aB" "Ab" "ab" "aC" "AC" "Ac" "ac" "BA" "Ba" "bA" "ba" "BB" "bB" +[18] "Bb" "bb" "bC" "BC" "Bc" "bc" "CA" "Ca" "cA" "ca" "CB" "cB" "Cb" "cb" "cC" "CC" "Cc" "cc" +StringCompare case-sensitive sorting: +[ 0] "aa" "aA" "Aa" "AA" "ab" "aB" "Ab" "AB" "ac" "aC" "Ac" "AC" "ba" "bA" "Ba" "BA" "bb" "bB" +[18] "Bb" "BB" "bc" "bC" "Bc" "BC" "ca" "cA" "Ca" "CA" "cb" "cB" "Cb" "CB" "cc" "cC" "Cc" "CC" + +``` + +The output shows the differences in these three modes. diff --git a/skills/mql5/references/book/03-common/0149-common-strings-strings-case-trim.md b/skills/mql5/references/book/03-common/0149-common-strings-strings-case-trim.md new file mode 100644 index 0000000..5b8fd17 --- /dev/null +++ b/skills/mql5/references/book/03-common/0149-common-strings-strings-case-trim.md @@ -0,0 +1,56 @@ +# Changing the character case and trimming spaces + +Working with texts often implies the use of some standard operations, such as converting all characters to upper or lower case and removing extra empty characters (for example, spaces) at the beginning or end of a string. For these purposes, the MQL5 API provides four corresponding functions. All of them modify the string in place, that is, directly in the available buffer (if it is already allocated). + +The input parameter of all functions is a reference to a string, i.e., only variables (not expressions) can be passed to them, and not constant variables since the functions involve modifying the argument. + +The test script for all functions follows the relevant descriptions. + +bool StringToLower(string &variable) + +bool StringToUpper(string &variable) + +The functions convert all characters of the specified string to the appropriate case: StringToLower to lowercase letters, and StringToUpper to uppercase. This includes support for national languages available at the Windows system level. + +If successful, it returns true. In case of an error, it returns false. + +int StringTrimLeft(string &variable) + +int StringTrimRight(string &variable) + +The function removes carriage return ('\r'), line feed ('\n'), spaces (' '), tabs ('\t') and some other non-displayable characters at the beginning (for StringTrimLeft) or end (for StringTrimRight) of a string. If there are empty spaces inside the string (between the displayed characters), they will be preserved. + +The function returns the number of characters removed. + +The StringModify.mq5 file demonstrates the operation of the above functions. + +``` +void OnStart() +{ +   string text = "  \tAbCdE F1  "; +               // ↑        ↑  ↑ +               // |        |  └2 spaces +               // |        └space +               // └2 spaces and tab +   PRT(StringToLower(text));   // 'true' +   PRT(text);                  // '  \tabcde f1  ' +   PRT(StringToUpper(text));   // 'true' +   PRT(text);                  // '  \tABCDE F1  ' +   PRT(StringTrimLeft(text));  // '3' +   PRT(text);                  // 'ABCDE F1  ' +   PRT(StringTrimRight(text)); // '2' +   PRT(text);                  // 'ABCDE F1' +   PRT(StringTrimRight(text)); // '0'  (there is nothing else to delete) +   PRT(text);                  // 'ABCDE F1' +                               //       ↑ +                               //       └the space inside remains +    +   string russian = "Russian text"; +   PRT(StringToUpper(russian));  // 'true' +   PRT(russian);                 // 'RUSSIAN TEXT'   +   string german = "straßenführung"; +   PRT(StringToUpper(german));   // 'true' +   PRT(german);                  // 'STRAßENFÜHRUNG' +} + +``` diff --git a/skills/mql5/references/book/03-common/0150-common-strings-strings-find-replace-split.md b/skills/mql5/references/book/03-common/0150-common-strings-strings-find-replace-split.md new file mode 100644 index 0000000..e34e4fd --- /dev/null +++ b/skills/mql5/references/book/03-common/0150-common-strings-strings-find-replace-split.md @@ -0,0 +1,182 @@ +# Finding, replacing, and extracting string fragments + +Perhaps the most popular operations when working with strings are finding and replacing fragments, as well as extracting them. In this section, we will study the MQL5 API functions that will help solve these problems. Examples of their use are summarized in the StringFindReplace.mq5 file. + +int StringFind(string value, string wanted, int start = 0) + +The function searches for the substring wanted in the string value, starting from the position start. If the substring is found, the function will return the position where it starts, with the characters in the string numbered starting from 0. Otherwise, the function will return -1. Both parameters are passed by value, which allows processing not only variables but also intermediate results of calculations (expressions, function calls). + +The search is performed based on a strict match of characters, i.e., it is case-sensitive. If you want to search in a case-insensitive way, you must first convert the source string to a single case using [StringToLower](/en/book/common/strings/strings_case_trim)[ or ](/en/book/common/strings/strings_case_trim)[StringToUpper](/en/book/common/strings/strings_case_trim). + +Let's try to count the number of occurrences of the desired substring in the text using StringFind. To do this, let's write a helper function CountSubstring which will call StringFind in a loop, gradually shifting the search starting position in the last parameter start. The loop continues as long as new occurrences of the substring are found. + +``` +int CountSubstring(const string value, const string wanted) +{ +   // indent back because of the increment at the beginning of the loop +   int cursor = -1; +   int count = -1; +   do +   { +      ++count; +      ++cursor; // search continues from the next position +      // get the position of the next substring, or -1 if there are no matches +      cursor = StringFind(value, wanted, cursor); +   } +   while(cursor > -1); +   return count; +} + +``` + +It is important to note that the presented implementation looks for substrings that can overlap. This is because the current position is changed by 1 (++cursor) before it starts looking for the next occurrence. As a result, when searching for, let's say, the substring "AAA" in the string "AAAAA", 3 matches will be found. The technical requirements for searching may differ from this behavior. In particular, there is a practice to continue searching after the position where the previously found fragment ended. In this case, it will be necessary to modify the algorithm so that the cursor moves with a step equal to StringLen(wanted). + +Let's call CountSubstring for different arguments in the OnStart function. + +``` +void OnStart() +{ +   string abracadabra = "ABRACADABRA"; +   PRT(CountSubstring(abracadabra, "A"));    // 5 +   PRT(CountSubstring(abracadabra, "D"));    // 1 +   PRT(CountSubstring(abracadabra, "E"));    // 0 +   PRT(CountSubstring(abracadabra, "ABRA")); // 2 +   ... +} + +``` + +int StringReplace(string &variable, const string wanted, const string replacement) + +The function replaces all found wanted substrings with the replacement substring in the variable string. + +The function returns the number of replacements made or -1 in case of an error. The error code can be obtained by calling the function [GetLastError](/en/book/common/environment/env_last_error). In particular, these can be out-of-memory errors or the use of an uninitialized string (NULL) as an argument. The variables and wanted parameters must be strings of non-zero length. + +When an empty string "" is given as the replacement argument, all occurrences of wanted are simply cut from the original string. + +If there were no substitutions, the result of the function is 0. + +Let's use the example of StringFindReplace.mq5 to check StringReplace in action. + +``` +   string abracadabra = "ABRACADABRA"; +   ... +   PRT(StringReplace(abracadabra, "ABRA", "-ABRA-")); // 2 +   PRT(StringReplace(abracadabra, "CAD", "-"));      // 1 +   PRT(StringReplace(abracadabra, "", "XYZ"));      // -1, error +   PRT(GetLastError());      // 5040, ERR_WRONG_STRING_PARAMETER +   PRT(abracadabra);                              // '-ABRA---ABRA-' +   ... + +``` + +Next, using the StringReplace function, let's try to execute one of the tasks encountered in the processing of arbitrary texts. We will try to ensure that a certain separator character is always used as a single character, i.e., sequences of several such characters must be replaced by one. Typically, this refers to spaces between words, but there may be other separators in technical data. Let's test our program for the separator '-'. + +We implement the algorithm as a separate function NormalizeSeparatorsByReplace: + +``` +int NormalizeSeparatorsByReplace(string &value, const ushort separator = ' ') +{ +   const string single = ShortToString(separator); +   const string twin = single + single; +   int count = 0; +   int replaced = 0; +   do +   { +      replaced = StringReplace(value, twin, single); +      if(replaced > 0) count += replaced; +   } +   while(replaced > 0); +   return count; +} + +``` + +The program tries to replace a sequence of two separators with one in a do-while loop, and the loop continues as long as the StringReplace function returns values greater than 0 (i.e., there is still something to replace). The function returns the total number of replacements made. + +In the function OnStart let's "clear" our inscription from multiple characters '-'. + +``` +   ... +   string copy1 = "-" + abracadabra + "-"; +   string copy2 = copy1; +   PRT(copy1);                                    // '--ABRA---ABRA--' +   PRT(NormalizeSeparatorsByReplace(copy1, '-')); // 4 +   PRT(copy1);                                    // '-ABRA-ABRA-' +   PRT(StringReplace(copy1, "-", ""));            // 1 +   PRT(copy1);                                    // 'ABRAABRA' +   ... + +``` + +int StringSplit(const string value, const ushort separator, string &result[]) + +The function splits the passed value string into substrings based on the given separator and puts them into the result array. The function returns the number of received substrings or -1 in case of an error. + +If there is no separator in the string, the array will have one element equal to the entire string. + +If the source string is empty or NULL, the function will return 0. + +To demonstrate the operation of this function, let's solve the previous problem in a new way using StringSplit. To do this, let's write the function NormalizeSeparatorsBySplit. + +``` +int NormalizeSeparatorsBySplit(string &value, const ushort separator = ' ') +{ +   const string single = ShortToString(separator); +    +   string elements[]; +   const int n = StringSplit(value, separator, elements); +   ArrayPrint(elements); // debug +    +   StringFill(value, 0); // result will replace original string +    +   for(int i = 0; i < n; ++i) +   { +      // empty strings mean delimiters, and we only need to add them +      // if the previous line is not empty (i.e. not a separator either) +      if(elements[i] == "" && (i == 0 || elements[i - 1] != "")) +      { +         value += single; +      } +      else // all other lines are joined together "as is" +      { +         value += elements[i]; +      } +   } +    +   return n; +} + +``` + +When separators occur one after another in the source text, the corresponding element in the output array StringSplit turns out to be an empty string "". Also, an empty string will be at the beginning of the array if the text starts with a separator, and at the end of the array if the text ends with the separator. + +To get "cleared" text, you need to add all non-empty strings from the array, "gluing" them with single separator characters. Moreover, only those empty elements in which the previous element of the array is also not empty should be converted into a separator. + +Of course, this is only one of the possible options for implementing this functionality. Let's check it in the OnStart function. + +``` +   ... +   string copy2 = "-" + abracadabra + "-";        // '--ABRA---ABRA--' +   PRT(NormalizeSeparatorsBySplit(copy2, '-'));   // 8 +   // debug output of split array (inside function): +   // ""     ""     "ABRA" ""     ""     "ABRA" ""     "" +   PRT(copy2);                                    // '-ABRA-ABRA-' + +``` + +string StringSubstr(string value, int start, int length = -1) + +The function extracts from the passed text value a substring starting at the specified position start, of the length length. The starting position can be from 0 to the length of the string minus 1. If the length length is -1 or more than the number of characters from start to the end of the string, the rest of the string will be extracted in full. + +The function returns a substring or an empty string if the parameters are incorrect. + +Let's see how it works. + +``` +   PRT(StringSubstr("ABRACADABRA", 4, 3));        // 'CAD' +   PRT(StringSubstr("ABRACADABRA", 4, 100));      // 'CADABRA' +   PRT(StringSubstr("ABRACADABRA", 4));           // 'CADABRA' +   PRT(StringSubstr("ABRACADABRA", 100));         // '' + +``` diff --git a/skills/mql5/references/book/03-common/0151-common-strings-strings-codepages.md b/skills/mql5/references/book/03-common/0151-common-strings-strings-codepages.md new file mode 100644 index 0000000..c591b36 --- /dev/null +++ b/skills/mql5/references/book/03-common/0151-common-strings-strings-codepages.md @@ -0,0 +1,290 @@ +# Working with symbols and code pages + +Since strings are made up of characters, it is sometimes necessary or simply more convenient to manipulate individual characters or groups of characters in a string at the level of their integer codes. For example, you need to read or replace characters one at a time or convert them into arrays of integer codes for transmission over communication protocols or into third-party programming interfaces of [dynamic libraries](/en/book/advanced/libraries/libraries_dll) DLL. In all such cases, passing strings as text can be accompanied by various difficulties: + +- ensuring the correct encoding (of which there are a great many, and the choice of a specific one depends on the operating system locale, program settings, the configuration of the servers with which communication is carried out, and much more) +- conversion of national language characters from the local text encoding to Unicode and vice versa +- allocation and deallocation of memory in a unified way + +The use of arrays with integer codes (while such use actually produces a binary rather than a textual representation of the string) simplifies these problems. + +The MQL5 API provides a set of functions to operate on individual characters or their groups, taking into account encoding features. + +Strings in MQL5 contain characters in two-byte Unicode encoding. This provides universal support for the entire variety of national alphabets in a single (but very large) character table. Two bytes allow the encoding of 65535 elements. + +The default character type is ushort. However, if necessary, the string can be converted to a sequence of single-byte uchar characters in a specific language encoding. This conversion may be accompanied by the loss of some information (in particular, letters that are not in the localized character table may "lose" umlauts or even "turn" into some kind of substitute character: depending on the context, it can be displayed differently, but usually as ' ?' or a square character). + +To avoid problems with texts that may contain arbitrary characters, it is recommended that you always use Unicode. An exception can be made if some external services or programs that should be integrated with your MQL program do not support Unicode, or if the text is intended from the beginning to store a limited set of characters (for example, only numbers and Latin letters). + +When converting to/from single-byte characters, the MQL5 API uses the ANSI encoding by default, depending on the current Windows settings. However, the developer can specify a different code table (see further functions CharArrayToString, StringToCharArray). + +Examples of using the functions described below are given in the StringSymbols.mq5 file. + +bool StringSetCharacter(string &variable, int position, ushort character) + +The function changes the character at position to the character value in the passed variable string. The number must be between 0 and the string length ([StringLen](/en/book/common/strings/strings_init)) minus 1. + +If the character to be written is 0, it specifies a new line ending (acts as a terminal zero), i.e. the length of the line becomes equal to position. The size of the buffer allocated for the line does not change. + +If the position parameter is equal to the length of the string and the character being written is not equal to 0, then the character is added to the string and its length is increased by 1. This is equivalent to the expression: variable += ShortToString(character). + +The function returns true upon successful completion, or false in case of error. + +``` +void OnStart() +{ +   string numbers = "0123456789"; +   PRT(numbers); +   PRT(StringSetCharacter(numbers, 7, 0));   // cut off at the 7th character +   PRT(numbers);                             // 0123456 +   PRT(StringSetCharacter(numbers, StringLen(numbers), '*')); // add '*' +   PRT(numbers);                             // 0123456* +   ... +} + +``` + +ushort StringGetCharacter(string value, int position) + +The function returns the code of the character located at the specified position in the string. The position number must be between 0 and the string length ([StringLen](/en/book/common/strings/strings_init)) minus 1. In case of an error, the function will return 0. + +The function is equivalent to writing using the operator '[]': value[position]. + +``` +   string numbers = "0123456789"; +   PRT(StringGetCharacter(numbers, 5));      // 53 = code '5' +   PRT(numbers[5]);                          // 53 - is the same  + +``` + +string CharToString(uchar code) + +The function converts the ANSI code of a character to a single-character string. Depending on the set Windows code page, the upper half of the codes (greater than 127) can generate different letters (the character style is different, while the code remains the same). For example, the symbol with the code 0xB8 (184 in decimal) denotes a cedilla (lower hook) in Western European languages, while in the Russian language the letter 'ё' is located here. Here's another example: + +``` +   PRT(CharToString(0xA9));   // "©" +  PRT(CharToString(0xE6));   // "æ", "ж", or another character +                             // depending on your Windows locale + +``` + +string ShortToString(ushort code) + +The function converts the Unicode code of a character to a single-character string. For the code parameter, you can use a literal or an integer. For example, the Greek capital letter "sigma" (the sign of the sum in mathematical formulas) can be specified as 0x3A3 or 'Σ'. + +``` +   PRT(ShortToString(0x3A3)); // "Σ" +   PRT(ShortToString('Σ'));   // "Σ" + +``` + +int StringToShortArray(const string text, ushort &array[], int start = 0, int count = -1) + +The function converts a string to a sequence of ushort character codes that are copied to the specified location in the array: starting from the element numbered start (0 by default, that is, the beginning of the array) and in the amount of count. + +Please note: the start parameter refers to the position in the array, not in the string. If you want to convert part of a string, you must first extract it using the [StringSubstr](/en/book/common/strings/strings_find_replace_split) function. + +If the count parameter is equal to -1 (or WHOLE_ARRAY), all characters up to the end of the string (including the terminal null) or characters in accordance with the size of the array, if it is a fixed size, are copied. + +In the case of a dynamic array, it will be automatically increased in size if necessary. If the size of a dynamic array is greater than the length of the string, then the size of the array is not reduced. + +To copy characters without a terminating null, you must explicitly call StringLen as the count argument. Otherwise, the length of the array will be by 1 more than the length of the string (and 0 in the last element). + +The function returns the number of copied characters. + +``` +   ... +   ushort array1[], array2[]; // dynamic arrays  +   ushort text[5];            // fixed size array  +   string alphabet = "ABCDEАБВГД"; +   // copy with the terminal '0' +   PRT(StringToShortArray(alphabet, array1)); // 11 +   ArrayPrint(array1); // 65   66   67   68   69 1040 1041 1042 1043 1044    0 +   // copy without the terminal '0' +   PRT(StringToShortArray(alphabet, array2, 0, StringLen(alphabet))); // 10 +   ArrayPrint(array2); // 65   66   67   68   69 1040 1041 1042 1043 1044 +   // copy to a fixed array  +   PRT(StringToShortArray(alphabet, text)); // 5 +   ArrayPrint(text); // 65 66 67 68 69 +   // copy beyond the previous limits of the array  +   // (elements [11-19] will be random) +   PRT(StringToShortArray(alphabet, array2, 20)); // 11 +   ArrayPrint(array2); +   /* +   [ 0]    65    66    67    68    69  1040  1041  1042 +         1043  1044     0     0     0     0     0 14245 +   [16] 15102 37754 48617 54228    65    66    67    68 +           69  1040  1041  1042  1043  1044     0 +   */ + +``` + +Note that if the position for copying is beyond the size of the array, then the intermediate elements will be allocated but not initialized. As a result, they may contain random data (highlighted in yellow above). + +string ShortArrayToString(const ushort &array[], int start = 0, int count = -1) + +The function converts part of the array with character codes to a string. The range of array elements is set by parameters start and count, the starting position, and quantity, respectively. The parameter start must be between 0 and the number of elements in the array minus 1. If count is equal to -1 (or WHOLE_ARRAY) all elements up to the end of the array or up to the first null are copied. + +Using the same example from StringSymbols.mq5, let's try to convert an array into the array2 string, which has a size of 30. + +``` +   ... +   string s = ShortArrayToString(array2, 0, 30); +   PRT(s); // "ABCDEАБВГД", additional random characters may appear here + +``` + +Because in the array array2 the string "ABCDEABCD" was copied twice, and specifically, firstly to the very beginning, and the second time —at offset 20, the intermediate characters will be random and able to form a longer string than we did. + +int StringToCharArray(const string text, uchar &array[], int start = 0, int count = -1, uint codepage = CP_ACP) + +The function converts the text string into a sequence of single-byte characters that are copied to the specified location in the array: starting from the element numbered start (0 by default, that is, the beginning of the array) and in the amount of count. The copying process converts characters from Unicode to the selected code page codepage — by default, CP_ACP, which means the language of the Windows operating system (more on this below). + +If the count parameter is equal to -1 (or WHOLE_ARRAY), all characters up to the end of the string (including the terminal null) or in accordance with the size of the array, if it is a fixed size, are copied. + +In the case of a dynamic array, it will be automatically increased in size if necessary. If the size of a dynamic array is greater than the length of the string, then the size of the array is not reduced. + +To copy characters without a terminating null, you must explicitly call [StringLen](/en/book/common/strings/strings_init) as an argument count. + +The function returns the number of copied characters. + +See the list of valid code pages for the parameter codepage in the documentation. Here are some of the widely used ANSI code pages: + +| Language | Code | +| --- | --- | +| Central European Latin | 1250 | +| Cyrillic | 1251 | +| Western European Latin | 1252 | +| Greek | 1253 | +| Turkish | 1254 | +| Hebrew | 1255 | +| Arab | 1256 | +| Baltic | 1257 | + +Thus, on computers with Western European languages, CP_ACP is 1252, and, for example, on computers with Russian, it is 1251. + +During the conversion process, some characters may be converted with loss of information, since the Unicode table is much larger than ANSI (each ANSI code table has 256 characters). + +In this regard, CP_UTF8 is of particular importance among all the CP_*** constants. It allows national characters to be properly preserved by variable-length encoding: the resulting array still stores bytes, but each national character can span multiple bytes, written in a special format. Because of this, the length of the array can be significantly larger than the length of the string. UTF-8 encoding is widely used on the Internet and in various software. Incidentally, UTF stands for Unicode Transformation Format, and there are other modifications, notably UTF-16 and UTF-32. + +We will consider an example for StringToCharArray after we get acquainted with the "inverse" function CharArrayToString: their work must be demonstrated in conjunction. + +string CharArrayToString(const uchar &array[], int start = 0, int count = -1, uint codepage = CP_ACP) + +The function converts an array of bytes or part of it into a string. The array must contain characters in a specific encoding. The range of array elements is set by parameters start and count, the starting position, and quantity, respectively. The parameter start must be between 0 and the number of elements in the array. When count is equal to -1 (or WHOLE_ARRAY) all elements up to the end of the array or up to the first null are copied. + +Let's see how the functions StringToCharArray and CharArrayToString work with different national characters with different code page settings. A test script StringCodepages.mq5 has been prepared for this. + +Two lines will be used as the test subjects - in Russian and German: + +``` +void OnStart() +{ +   Print("Locales"); +   uchar bytes1[], bytes2[]; +  +   string german = "straßenführung"; +   string russian = "Russian text"; +   ... + +``` + +We will copy them into arrays bytes1 and bytes2 and then restore them to strings. + +First, let's convert the German text using the European code page 1252. + +``` +   ... +   StringToCharArray(german, bytes1, 0, WHOLE_ARRAY, 1252); +   ArrayPrint(bytes1); +   // 115 116 114  97 223 101 110 102 252 104 114 117 110 103   0 + +``` + +On European copies of Windows, this is equivalent to a simpler function call with default parameters, because there CP_ACP = 1252: + +``` +   StringToCharArray(german, bytes1); + +``` + +Then we restore the text from the array with the following call and make sure that everything matches the original: + +``` +   ... +   PRT(CharArrayToString(bytes1, 0, WHOLE_ARRAY, 1252)); +   // CharArrayToString(bytes1,0,WHOLE_ARRAY,1252)='straßenführung' + +``` + +Now let's try to convert the Russian text in the same European encoding (or you can call StringToCharArray(english, bytes2) in the Windows environment where CP_ACP is set to 1252 as the default code page): + +``` +   ... +   StringToCharArray(russian, bytes2, 0, WHOLE_ARRAY, 1252); +   ArrayPrint(bytes2); +   // 63 63 63 63 63 63 63 32 63 63 63 63 63  0 + +``` + +Here you can already see that there was a problem during the conversion because 1252 does not have Cyrillic. Restoring a string from an array clearly shows the essence: + +``` +   ... +   PRT(CharArrayToString(bytes2, 0, WHOLE_ARRAY, 1252)); +   // CharArrayToString(bytes2,0,WHOLE_ARRAY,1252)='??????? ?????' + +``` + +Let's repeat the experiment in a conditional Russian environment, i.e., we will convert both strings back and forth using the Cyrillic code page 1251. + +``` +   ... +   StringToCharArray(russian, bytes2, 0, WHOLE_ARRAY, 1251); +   // on Russian Windows, this call is equivalent to a simpler one +   // StringToCharArray(russian, bytes2); +   // because CP_ACP = 1251 +   ArrayPrint(bytes2); // this time the character codes are meaningful +   // 208 243 241 241 234 232 233  32 210 229 234 241 242   0 +    +   // restore the string and make sure it matches the original +   PRT(CharArrayToString(bytes2, 0, WHOLE_ARRAY, 1251)); +   // CharArrayToString(bytes2,0,WHOLE_ARRAY,1251)='Русский Текст' +    +   // and for the German text... +   StringToCharArray(german, bytes1, 0, WHOLE_ARRAY, 1251); +   ArrayPrint(bytes1); +   // 115 116 114  97  63 101 110 102 117 104 114 117 110 103   0 +   // if we compare this content of bytes1 with the previous version, +   // it's easy to see that a couple of characters are affected; here's what happened: +   // 115 116 114  97 223 101 110 102 252 104 114 117 110 103   0 +    +   // restore the string to see the differences visually: +   PRT(CharArrayToString(bytes1, 0, WHOLE_ARRAY, 1251)); +   // CharArrayToString(bytes1,0,WHOLE_ARRAY,1251)='stra?enfuhrung' +   // specific German characters were corrupted + +``` + +Thus, the fragility of single-byte encodings is evident. + +Finally, let's enable the CP_UTF8 encoding for both test strings. This part of the example will work stably regardless of Windows settings. + +``` +   ... +   StringToCharArray(german, bytes1, 0, WHOLE_ARRAY, CP_UTF8); +   ArrayPrint(bytes1); +   // 115 116 114  97 195 159 101 110 102 195 188 104 114 117 110 103   0 +   PRT(CharArrayToString(bytes1, 0, WHOLE_ARRAY, CP_UTF8)); +   // CharArrayToString(bytes1,0,WHOLE_ARRAY,CP_UTF8)='straßenführung' +    +   StringToCharArray(russian, bytes2, 0, WHOLE_ARRAY, CP_UTF8); +   ArrayPrint(bytes2); +   // 208 160 209 131 209 129 209 129 208 186 208 184 208 185 +   //  32 208 162 208 181 208 186 209 129 209 130   0 +   PRT(CharArrayToString(bytes2, 0, WHOLE_ARRAY, CP_UTF8)); +   // CharArrayToString(bytes2,0,WHOLE_ARRAY,CP_UTF8)='Русский Текст' + +``` + +Note that both of the UTF-8 encoded strings required larger arrays than ANSI ones. Moreover, the array with the Russian text has actually become 2 times longer, because all letters now occupy 2 bytes. Those who wish can find details in open sources on how exactly the UTF-8 encoding works. In the context of this book, it is important for us that the MQL5 API provides ready-made functions to work with. diff --git a/skills/mql5/references/book/03-common/0152-common-strings-strings-format.md b/skills/mql5/references/book/03-common/0152-common-strings-strings-format.md new file mode 100644 index 0000000..ba894a4 --- /dev/null +++ b/skills/mql5/references/book/03-common/0152-common-strings-strings-format.md @@ -0,0 +1,327 @@ +# Universal formatted data output to a string + +When generating a string to display to the user, to save to a file, or to send over the Internet, it may be necessary to include the values of several variables of different types in it. This problem can be solved by explicitly casting all variables to the type (string) and adding the resulting strings, but in this case, the MQL code instruction will be long and difficult to understand. It would probably be more convenient to use the [StringConcatenate](/en/book/common/strings/strings_concatenation) function, but this method does not completely solve the problem. + +The fact is that a string usually contains not only variables, but also some text inserts that act as connecting links and provide the correct structure of the overall message. It turns out that pieces of formatting text are mixed with variables. This kind of code is hard to maintain, which goes against one of the well-known principles of programming: the separation of content and presentation. + +There is a special solution for this problem: the StringFormat function. + +The same scheme applies to another MQL5 API function: [PrintFormat](/en/book/common/output/output_print). + +string StringFormat(const string format, ...) + +The function converts arbitrary built-in type arguments to a string according to the specified format. The first parameter is the template of the string to be prepared, in which the places for inserting variables are indicated in a special way and the format of their output is determined. These control commands may be interspersed with plain text, which is copied to the output string unchanged. The following function parameters, separated by commas, list all the variables in the order and types that are reserved for them in the template. + +![Interaction of the format string and StringFormat arguments](pics/sprintf.png) + +Interaction of the format string and StringFormat arguments + +Each variable insertion point in a string is marked with a format specifier: the character '%', after which several settings can be specified. + +The format string is parsed from left to right. When the first specifier (if any) is encountered, the value of the first parameter after the format string is converted and added to the resulting string according to the specified settings. The second specifier causes the second parameter to be converted and printed, and so on, until the end of the format string. All other characters in the pattern between the specifiers are copied unchanged into the resulting string. + +The template may not contain any specifier, that is, it can be a simple string. In this case, you need to pass a dummy argument to the function in addition to the string (the argument will not be placed in the string). + +If you want to display the percent sign in the template, then you should write it twice in a row %%. If the % sign is not doubled, then the next few characters following % are always parsed as a specifier. + +A mandatory attribute of a specifier is a symbol that indicates the expected type and interpretation of the next function argument. Let's conditionally call this symbol T. Then, in the simplest case, one format specifier looks like %T. + +In a generalized form, the specifier can consist of several more fields (optional fields are indicated in square brackets): + +%[Z][W][.P][M]T + +Each field performs its function and takes one of the allowed values. Next, we will gradually consider all the fields. + +Type T + +For integers, the following characters can be used as T, with an explanation of how the corresponding numbers are displayed in the string: + +- c — Unicode character +- C — ANSI character +- d, i — signed decimal +- o — unsigned octal +- u — unsigned decimal +- x — unsigned hexadecimal (lowercase) +- X — unsigned hexadecimal (capital letters) + +Recall that according to the method of internal data storage, integer types also include built-in MQL5 types datetime, color, bool and enumerations. + +For real numbers, the following symbols are applicable as T: + +- e — scientific format with exponent (lowercase 'e') +- E — scientific format with exponent (capital 'E') +- f — normal format +- g — analog of f or e (the most compact form is chosen) +- G — analog of f or E (the most compact form is chosen) +- a — scientific format with exponent, hexadecimal (lowercase) +- A — scientific format with exponent, hexadecimal (capital letters) + +Finally, there is only one version of the T character available for strings: s. + +Size of integers M + +For integer types, you can additionally explicitly specify the size of the variable in bytes by prefixing T with one of the following characters or combinations of them (we have generalized them under the letter M): + +- h — 2 bytes (short, ushort) +- l (lowercase L) — 4 bytes (int, uint) +- I32 (capital i) — 4 bytes (int, uint) +- ll (two lowercase Ls) — 8 bytes (long) +- I64 (capital i) — 8 bytes (long, ulong) + +Width W + +The W field is a non-negative decimal number that specifies the minimum number of character spaces available for the formatted value. If the value of the variable fits into fewer characters, then the corresponding number of spaces is added to the left or right. The left or right side is selected depending on the alignment (see the flag further '—' in the Z field). If the '0' flag is present, the corresponding number of zeros is added in front of the output value. If the number of characters to be output is greater than the specified width, then the width setting is ignored and the output value is not truncated. + +If an asterisk '*' is specified as the width, then the width of the output value should be specified in the list of passed parameters. It should be a value of type int at the position preceding the variable being formatted. + +Precision P + +The P field also contains a non-negative decimal number and is always preceded by a dot '.'. For integer T, this field specifies the minimum number of significant digits. If the value fits in fewer digits, it is prepended with zeros. + +For real numbers, P specifies the number of decimal places (default is 6), except for the g and G specifiers, for which P is the total number of significant digits (mantissa and decimal). + +For a string, P specifies the number of characters to display. If the string length exceeds the precision value, then the string will be shown as truncated. + +If the asterisk '*' is specified as the precision, it is treated in the same way as for the width but controls the precision. + +Fixed width and/or precision, together with the right-alignment, makes it possible to display values in a neat column. + +Flags Z + +Finally, the Z field describes the flags: + +- - (minus) — left alignment within the specified width (in the absence of the flag, right alignment is done); +- + (plus) — unconditional display of a '+' or '-' sign before the value (without this flag, only '-' is displayed for negative values); +- 0 — zeros are added before the output value if it is less than the specified width; +- (space) — a space is placed before the displayed value if it is signed and positive; +- # — controls the display of octal and hexadecimal number prefixes in formats o, x or X (for example, for the format x prefix "0x" is added before the displayed number, for the format X — prefix "0X"), decimal point in real numbers (formats e, E, a or A) with a zero fractional part, and some other nuances. + +You can learn more about the possibilities of formatted output to a string in the [documentation](https://www.mql5.com/ru/docs/common/printformat). + +The total number of function parameters cannot exceed 64. + +If the number of arguments passed to the function is greater than the number of specifiers, then the extra arguments are omitted. + +If the number of specifiers in the format string is greater than the arguments, then the system will try to display zeros instead of missing data, but a text warning ("missing string parameter") will be embedded for string specifiers. + +If the type of the value does not match the type of the corresponding specifier, the system will try to read the data from the variable in accordance with the format and display the resulting value (it may look strange due to a misinterpretation of the internal bit representation of the real data). In the case of strings, a warning ("non-string passed") may be embedded in the result. + +Let's test the function with the script StringFormat.mq5. + +First, let's try different options for T and data type specifier. + +``` +PRT(StringFormat("[Infinity Sign] Unicode (ok): %c; ANSI (overflow): %C",  +   '∞', '∞')); +PRT(StringFormat("short (ok): %hi, short (overflow): %hi",  +   SHORT_MAX, INT_MAX)); +PRT(StringFormat("int (ok): %i, int (overflow): %i",  +   INT_MAX, LONG_MAX)); +PRT(StringFormat("long (ok): %lli, long (overflow): %i",  +   LONG_MAX, LONG_MAX)); +PRT(StringFormat("ulong (ok): %llu, long signed (overflow): %lli",  +   ULONG_MAX, ULONG_MAX)); + +``` + +Both correct and incorrect specifiers are represented here (incorrect ones come second in each instruction and are marked with the word "overflow" since the value passed does not fit in the format type). + +Here's what happens in the log (the breaks of long lines here and below are made for publication): + +``` +StringFormat(Plain string,0)='Plain string' +StringFormat([Infinity Sign] Unicode: %c; ANSI: %C,'∞','∞')= +   '[Infinity Sign] Unicode (ok): ∞; ANSI (overflow):  ' +StringFormat(short (ok): %hi, short (overflow): %hi,SHORT_MAX,INT_MAX)= +   'short (ok): 32767, short (overflow): -1' +StringFormat(int (ok): %i, int (overflow): %i,INT_MAX,LONG_MAX)= +   'int (ok): 2147483647, int (overflow): -1' +StringFormat(long (ok): %lli, long (overflow): %i,LONG_MAX,LONG_MAX)= +   'long (ok): 9223372036854775807, long (overflow): -1' +StringFormat(ulong (ok): %llu, long signed (overflow): %lli,ULONG_MAX,ULONG_MAX)= +   'ulong (ok): 18446744073709551615, long signed (overflow): -1' + +``` + +All of the following instructions are correct: + +``` +PRT(StringFormat("ulong (ok): %I64u", ULONG_MAX)); +PRT(StringFormat("ulong (HEX): %I64X, ulong (hex): %I64x",  +   1234567890123456, 1234567890123456)); +PRT(StringFormat("double PI: %f", M_PI)); +PRT(StringFormat("double PI: %e", M_PI)); +PRT(StringFormat("double PI: %g", M_PI)); +PRT(StringFormat("double PI: %a", M_PI)); +PRT(StringFormat("string: %s", "ABCDEFGHIJ")); + +``` + +The result of their work is shown below: + +``` +StringFormat(ulong (ok): %I64u,ULONG_MAX)= +   'ulong (ok): 18446744073709551615' +StringFormat(ulong (HEX): %I64X, ulong (hex): %I64x,1234567890123456,1234567890123456)= +   'ulong (HEX): 462D53C8ABAC0, ulong (hex): 462d53c8abac0' +StringFormat(double PI: %f,M_PI)='double PI: 3.141593' +StringFormat(double PI: %e,M_PI)='double PI: 3.141593e+00' +StringFormat(double PI: %g,M_PI)='double PI: 3.14159' +StringFormat(double PI: %a,M_PI)='double PI: 0x1.921fb54442d18p+1' +StringFormat(string: %s,ABCDEFGHIJ)='string: ABCDEFGHIJ' + +``` + +Now let's look at the various modifiers. + +With right alignment (by default) and a fixed field width (number of characters), we can use different options for padding the resulting string on the left: with a space or zeros. In addition, for any alignment, you can enable or disable the explicit indication of the sign of the value (so that not only minus is displayed for negative, but also plus for positive). + +``` +PRT(StringFormat("space padding: %10i", SHORT_MAX)); +PRT(StringFormat("0-padding: %010i", SHORT_MAX)); +PRT(StringFormat("with sign: %+10i", SHORT_MAX)); +PRT(StringFormat("precision: %.10i", SHORT_MAX)); + +``` + +We get the following in the log: + +``` +StringFormat(space padding: %10i,SHORT_MAX)='space padding:      32767' +StringFormat(0-padding: %010i,SHORT_MAX)='0-padding: 0000032767' +StringFormat(with sign: %+10i,SHORT_MAX)='with sign:     +32767' +StringFormat(precision: %.10i,SHORT_MAX)='precision: 0000032767' + +``` + +To align to the left, you must use the '-' (minus) flag, the addition of the string to the specified width occurs on the right: + +``` +PRT(StringFormat("no sign (default): %-10i", SHORT_MAX)); +PRT(StringFormat("with sign: %+-10i", SHORT_MAX)); + +``` + +Result: + +``` +StringFormat(no sign (default): %-10i,SHORT_MAX)='no sign (default): 32767     ' +StringFormat(with sign: %+-10i,SHORT_MAX)='with sign: +32767    ' + +``` + +If necessary, we can show or hide the sign of the value (by default, only minus is displayed for negative values), add a space for positive values, and thus ensure the same formatting when you need to display variables in a column: + +``` +PRT(StringFormat("default: %i", SHORT_MAX));  // standard +PRT(StringFormat("default: %i", SHORT_MIN)); +PRT(StringFormat("space  : % i", SHORT_MAX)); // extra space for positive +PRT(StringFormat("space  : % i", SHORT_MIN)); +PRT(StringFormat("sign   : %+i", SHORT_MAX)); // force sign output +PRT(StringFormat("sign   : %+i", SHORT_MIN)); + +``` + +Here's what it looks like in the log: + +``` +StringFormat(default: %i,SHORT_MAX)='default: 32767' +StringFormat(default: %i,SHORT_MIN)='default: -32768' +StringFormat(space  : % i,SHORT_MAX)='space  :  32767' +StringFormat(space  : % i,SHORT_MIN)='space  : -32768' +StringFormat(sign   : %+i,SHORT_MAX)='sign   : +32767' +StringFormat(sign   : %+i,SHORT_MIN)='sign   : -32768' + +``` + +Now let's compare how width and precision affect real numbers. + +``` +PRT(StringFormat("double PI: %15.10f", M_PI)); +PRT(StringFormat("double PI: %15.10e", M_PI)); +PRT(StringFormat("double PI: %15.10g", M_PI)); +PRT(StringFormat("double PI: %15.10a", M_PI)); +    +// default precision = 6 +PRT(StringFormat("double PI: %15f", M_PI)); +PRT(StringFormat("double PI: %15e", M_PI)); +PRT(StringFormat("double PI: %15g", M_PI)); +PRT(StringFormat("double PI: %15a", M_PI)); + +``` + +Result: + +``` +StringFormat(double PI: %15.10f,M_PI)='double PI:    3.1415926536' +StringFormat(double PI: %15.10e,M_PI)='double PI: 3.1415926536e+00' +StringFormat(double PI: %15.10g,M_PI)='double PI:     3.141592654' +StringFormat(double PI: %15.10a,M_PI)='double PI: 0x1.921fb54443p+1' +StringFormat(double PI: %15f,M_PI)='double PI:        3.141593' +StringFormat(double PI: %15e,M_PI)='double PI:    3.141593e+00' +StringFormat(double PI: %15g,M_PI)='double PI:         3.14159' +StringFormat(double PI: %15a,M_PI)='double PI: 0x1.921fb54442d18p+1' + +``` + +In the explicit width is not specified, the values are output without padding with spaces. + +``` +PRT(StringFormat("double PI: %.10f", M_PI)); +PRT(StringFormat("double PI: %.10e", M_PI)); +PRT(StringFormat("double PI: %.10g", M_PI)); +PRT(StringFormat("double PI: %.10a", M_PI)); + +``` + +Result: + +``` +StringFormat(double PI: %.10f,M_PI)='double PI: 3.1415926536' +StringFormat(double PI: %.10e,M_PI)='double PI: 3.1415926536e+00' +StringFormat(double PI: %.10g,M_PI)='double PI: 3.141592654' +StringFormat(double PI: %.10a,M_PI)='double PI: 0x1.921fb54443p+1' + +``` + +Setting the width and precision of values using the sign '*' and based on additional function arguments is performed as follows: + +``` +PRT(StringFormat("double PI: %*.*f", 12, 5, M_PI)); +PRT(StringFormat("string: %*s", 15, "ABCDEFGHIJ")); +PRT(StringFormat("string: %-*s", 15, "ABCDEFGHIJ")); + +``` + +Please note that 1 or 2 integer type values are passed before the output value, according to the number of asterisks '*' in the specifier: you can control the precision and the width separately or both together. + +``` +StringFormat(double PI: %*.*f,12,5,M_PI)='double PI:      3.14159' +StringFormat(string: %*s,15,ABCDEFGHIJ)='string:      ABCDEFGHIJ' +StringFormat(string: %-*s,15,ABCDEFGHIJ)='string: ABCDEFGHIJ     ' + +``` + +Finally, let's look at a few common formatting errors. + +``` +PRT(StringFormat("string: %s %d %f %s", "ABCDEFGHIJ")); +PRT(StringFormat("string vs int: %d", "ABCDEFGHIJ")); +PRT(StringFormat("double vs int: %d", M_PI)); +PRT(StringFormat("string vs double: %s", M_PI)); + +``` + +The first instruction has more specifiers than arguments. In other cases, the types of specifiers and passed values do not match. As a result, we get the following output: + +``` +StringFormat(string: %s %d %f %s,ABCDEFGHIJ)= +   'string: ABCDEFGHIJ 0 0.000000 (missed string parameter)' +StringFormat(string vs int: %d,ABCDEFGHIJ)='string vs int: 0' +StringFormat(double vs int: %d,M_PI)='double vs int: 1413754136' +StringFormat(string vs double: %s,M_PI)= +   'string vs double: (non-string passed)' + +``` + +Having a single format string in every StringFormat function call allows you to use it, in particular, to translate the external interface of programs and messages into different languages: simply download and substitute into StringFormat various format strings (prepared in advance) depending on user preferences or terminal settings. diff --git a/skills/mql5/references/book/03-common/0153-common-arrays.md b/skills/mql5/references/book/03-common/0153-common-arrays.md new file mode 100644 index 0000000..d051018 --- /dev/null +++ b/skills/mql5/references/book/03-common/0153-common-arrays.md @@ -0,0 +1,11 @@ +# Working with arrays + +It is difficult to imagine any program and especially one related to trading, without arrays. We have already studied the general principles of describing and using arrays in the [Arrays chapter](/en/book/basis/arrays). They are organically complemented by a set of built-in functions for working with arrays. + +Some of them provide ready-made implementations of the most commonly used array operations, such as finding the maximum and minimum, sorting, inserting, and deleting elements. + +However, there are a number of functions without which it is impossible to use arrays of specific types. In particular, a dynamic array must first allocate memory before working with it, and arrays with data for indicator buffers (we will study this MQL program type in Part 5 of the book) use a special order of element indexing, set by a special function. + +And we will begin looking at functions for working with arrays with the output operation to the log. We already saw it in previous chapters of the book and will be useful in many subsequent ones. + +Since MQL5 arrays can be multidimensional (from 1 to 4 dimensions), we will need to refer to the dimension numbers further in the text. We will call them numbers, starting with the first, which is more familiar geometrically and which emphasizes the fact that an array must have at least one dimension (even if it is empty). However, array elements for each dimension are numbered, as is customary in MQL5 (and in many other programming languages), from zero. Thus, for an array described as array[5][10], the first dimension is 5 and the second is 10. diff --git a/skills/mql5/references/book/03-common/0154-common-arrays-arrays-print.md b/skills/mql5/references/book/03-common/0154-common-arrays-arrays-print.md new file mode 100644 index 0000000..d4dd898 --- /dev/null +++ b/skills/mql5/references/book/03-common/0154-common-arrays-arrays-print.md @@ -0,0 +1,155 @@ +# Logging arrays + +Printing variables, arrays, and messages about the status of an MQL program to the log is the simplest means for informing the user, debugging, and diagnosing problems. As for the array, we can implement element-wise printing using the Print function which we already know from demo scripts. We will formally describe it a little later, in the section on [interaction with the user](/en/book/common/output). + +However, it is more convenient to entrust the whole routine related to iteration over elements and their accurate formatting to the MQL5 environment. The API provides a special ArrayPrint function for this purpose. + +We have already seen examples of working with this function in the [Using arrays](/en/book/basis/arrays/arrays_usage) section. Now let's talk about its capabilities in more detail. + +void ArrayPrint(const void &array[], uint digits = _Digits, const string separator = NULL, + +   ulong start = 0, ulong count = WHOLE_ARRAY, + +   ulong flags = ARRAYPRINT_HEADER | ARRAYPRINT_INDEX | ARRAYPRINT_LIMIT | ARRAYPRINT_DATE | ARRAYPRINT_SECONDS) + +The function logs an array using the specified settings. The array must be one of the built-in types or a simple structure type. A simple structure is a structure with fields of built-in types, with the exception of strings and dynamic arrays. The presence of class objects and pointers in the composition of the structure takes it out of the simple category. + +The array must have a dimension of 1 or 2. The formatting automatically adjusts to the array configuration and, if possible, displays it in a visual form (see below). Despite the fact that MQL5 supports arrays with dimensions of up to 4, the function does not display arrays with 3 or more dimensions, because it is difficult to represent them in a "flat" form. This happens without generating errors at the program compilation or execution step. + +All parameters except the first one can be omitted, and default values are defined for them. + +The digits parameter is used for arrays of real numbers and for numeric fields of structures. It sets the number of displayed characters in the fractional part of numbers. The default value is one of the [predefined chart variables](/en/book/applications/charts/charts_main_properties), namely _Digits which is the number of decimal places in the current chart's symbol price. + +The separating character separator is used to designate columns when displaying fields in an array of structures. With the default value (NULL), the function uses a space as a separator. + +The start and count parameters set the number of the starting element and the number of elements to be printed, respectively. By default, the function prints the entire array, but the result can be additionally affected by the presence of the ARRAYPRINT_LIMIT flag (see below). + +The flags parameter accepts a combination of flags that control various display features. Here are some of them: + +- ARRAYPRINT_HEADER outputs the header with the names of the fields of the structure before the array of structures; it does not affect arrays of non-structures. +- ARRAYPRINT_INDEX outputs indexes of elements by dimensions (for one-dimensional arrays, indexes are displayed on the left, for two-dimensional arrays they are displayed on the left and above). +- ARRAYPRINT_LIMIT is used for large arrays, and the output is limited to the first hundred and last hundred records (this limit is enabled by default). +- ARRAYPRINT_DATE is used for values of the datetime type to display the date. +- ARRAYPRINT_MINUTES is used for values of the datetime type to display the time to the nearest minute. +- ARRAYPRINT_SECONDS is used for values of the datetime type to display the time to the nearest second. + +Values of the datetime type are output by default in the format ARRAYPRINT_DATE | ARRAYPRINT_SECONDS. + +Values of type color are output in hexadecimal format. + +Enumeration values are displayed as integers. + +The function does not output nested arrays, structures, and pointers to objects. Three dots are displayed instead of those. + +The ArrayPrint.mq5 script demonstrates how the function works. + +The OnStart function provides definitions of several arrays (one-, two- and three-dimensional), which are output using ArrayPrint (with default settings). + +``` +void OnStart() +{ +   int array1D[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; +   double array2D[][5] = {{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}}; +   double array3D[][3][5] = +   { +      {{ 1,  2,  3,  4,  5}, { 6,  7,  8,  9, 10}, {11, 12, 13, 14, 15}}, +      {{16, 17, 18, 19, 20}, {21, 22, 23, 24, 25}, {26, 27, 28, 29, 30}}, +   }; +    +   Print("array1D"); +   ArrayPrint(array1D); +   Print("array2D"); +   ArrayPrint(array2D); +   Print("array3D"); +   ArrayPrint(array3D); +   ... +} + +``` + +We will get the following lines in the log: + +``` +array1D + 1  2  3  4  5  6  7  8  9 10 +array2D +         [,0]     [,1]     [,2]     [,3]     [,4] +[0,]  1.00000  2.00000  3.00000  4.00000  5.00000 +[1,]  6.00000  7.00000  8.00000  9.00000 10.00000 +array3D + +``` + +The array1D array is not large enough (it fits in one row), so indexes are not shown for it. + +The array2D array has multiple rows (indexes), and therefore their indexes are displayed (ARRAYPRINT_INDEX is enabled by default). + +Please note that since the script was run on the EURUSD chart with five-digit prices, _Digits=5, which affects the formatting of values of type double. + +The array3D array is ignored: no rows were output for it. + +Additionally, the Pair and SimpleStruct structures are defined in the script: + +``` +struct Pair +{ +   int x, y; +}; +    +struct SimpleStruct +{ +   double value; +   datetime time; +   int count; +   ENUM_APPLIED_PRICE price; +   color clr; +   string details; +   void *ptr; +   Pair pair; +}; + +``` + +SimpleStruct contains fields of built-in types, a pointer to void, as well as a field of type Pair. + +In the OnStart function, an array of type SimpleStruct is created and output using ArrayPrint in two modes: with default settings and with custom ones (the number of digits after the "comma" is 3, the separator is ";", the format for datetime is date only). + +``` +void OnStart() +{ +   ... +   SimpleStruct simple[] = +   { +      { 12.57839, D'2021.07.23 11:15', 22345, PRICE_MEDIAN, clrBlue, "text message"}, +      {135.82949, D'2021.06.20 23:45', 8569, PRICE_TYPICAL, clrAzure}, +      { 1087.576, D'2021.05.15 10:01:30', -3298, PRICE_WEIGHTED, clrYellow, "note"}, +   }; +   Print("SimpleStruct (default)"); +   ArrayPrint(simple); +    +   Print("SimpleStruct (custom)"); +   ArrayPrint(simple, 3, ";", 0, WHOLE_ARRAY, ARRAYPRINT_DATE); +} + +``` + +This produces the following result: + +``` +SimpleStruct (default) +       [value]              [time] [count] [type]    [clr]      [details] [ptr] [pair] +[0]   12.57839 2021.07.23 11:15:00   22345      5 00FF0000 "text message"   ...    ... +[1]  135.82949 2021.06.20 23:45:00    8569      6 00FFFFF0 null             ...    ... +[2] 1087.57600 2021.05.15 10:01:30   -3298      7 0000FFFF "note"           ...    ... +SimpleStruct (custom) +  12.578;2021.07.23;  22345;     5;00FF0000;"text message";  ...;   ... + 135.829;2021.06.20;   8569;     6;00FFFFF0;null          ;  ...;   ... +1087.576;2021.05.15;  -3298;     7;0000FFFF;"note"        ;  ...;   ... + +``` + +Please note that the log that we use in this case and in the previous sections is generated in the terminal and is available to the user in the tab Experts of the Toolbox window. However, in the future we will get acquainted with the tester, which provides the same execution environment for certain types of MQL programs (indicators and Expert Advisors) as the terminal itself. If they are launched in the tester, the ArrayPrint function and other related functions, which are described in the section [User interaction](/en/book/common/output), will output messages to the log of [testing agents](/en/book/automation/tester). + +  + +Until now, we have worked, and will continue to work for some time, only with scripts, and they can only be executed in the terminal. diff --git a/skills/mql5/references/book/03-common/0155-common-arrays-arrays-dynamic.md b/skills/mql5/references/book/03-common/0155-common-arrays-arrays-dynamic.md new file mode 100644 index 0000000..403be8f --- /dev/null +++ b/skills/mql5/references/book/03-common/0155-common-arrays-arrays-dynamic.md @@ -0,0 +1,317 @@ +# Dynamic arrays + +Dynamic arrays can change their size during program execution at the request of the programmer. Let's remember that to describe a dynamic array, you should leave the first pair of brackets after the array identifier empty. MQL5 requires that all subsequent dimensions (if there are more than one) must have a fixed size specified with a constant. + +It is impossible to dynamically increase the number of elements for any dimension "older" than the first one. In addition, due to the strict size description, arrays have a "square" shape, i.e., for example, it is impossible to construct a two-dimensional array with columns or rows of different lengths. If any of these restrictions are critical for the implementation of the algorithm, you should use not standard MQL5 arrays, but your own structures or classes written in MQL5. + +Note that if an array does not have a size in the first dimension, but does have an initialization list that allows you to determine the size, then such an array is a fixed-size array, not a dynamic one. + +For example, in the previous section, we used the array1D array: + +``` +int array1D[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + +``` + +Because of the initialization list, its size is known to the compiler, and therefore the array is fixed. + +Unlike this simple example, it is not always easy to determine whether a particular array in a real program is dynamic. In particular, an array can be passed as a parameter into a function. However, it may be important to know if an array is dynamic because memory can be manually allocated by calling ArrayResize only for such arrays. + +In such cases, the ArrayIsDynamic function allows you to determine the type of the array. + +Let's consider some technical descriptions of functions for working with dynamic arrays and then test them using the ArrayDynamic.mq5 script. + +bool ArrayIsDynamic(const void &array[]) + +The function checks if the passed array is dynamic. An array can be of any allowed dimension from 1 to 4. Array elements can be of any type. + +The function returns true for a dynamic array, or false in other cases (fixed array, or array with [timeseries](/en/book/applications/timeseries), controlled by the terminal itself or by the indicator). + +int ArrayResize(void &array[], int size, int reserve = 0) + +The function sets the new size in the first dimension of the dynamic array. An array can be of any allowed dimension from 1 to 4. Array elements can be of any type. + +If the reserve parameter is greater than zero, memory is allocated for the array with a reserve for the specified number of elements. This makes can increase the speed of the program which has many consecutive function calls. Until the new requested size of the array exceeds the current one taking into account the reserve, there will be no physical memory reallocation and new elements will be taken from the reserve. + +The function returns the new size of the array if its modification was successful, or -1 in case of an error. + +If the function is applied to a fixed array or timeseries, its size does not change. In these cases, if the requested size is less than or equal to the current size of the array, the function will return the value of the size parameter, otherwise, it will return -1. + +When increasing the size of an already existing array, all the data of its elements is preserved. The added elements are not initialized with anything and may contain arbitrary incorrect data ("garbage"). + +Setting the array size to 0, ArrayResize(array, 0), does not release the memory actually allocated for it, including a possible reserve. Such a call will only reset the metadata for the array. This is done for the purpose of optimizing future operations with the array. To force memory release, use ArrayFree (see below). + +It is important to understand that the reserve parameter is not used every time the function is called, but only at those moments when the reallocation of memory is actually performed, i.e., when the requested size exceeds the current capacity of the array including the reserve. To visually show how this works, we will create an incomplete copy of the internal array object and implement the twin function ArrayResize for it, and also the analogs ArrayFree and ArraySize, to have a complete toolkit. + +``` +template +struct DynArray +{ +   int size; +   int capacity; +   T memory[]; +}; +  +template +int DynArraySize(DynArray &array) +{ +   return array.size; +} +  +template +void DynArrayFree(DynArray &array) +{ +   ArrayFree(array.memory); +   ZeroMemory(array); +} +  +template +int DynArrayResize(DynArray &array, int size, int reserve = 0) +{ +   if(size > array.capacity) +   { +      static int temp; +      temp = array.capacity; +      long ul = (long)GetMicrosecondCount(); +      array.capacity = ArrayResize(array.memory, size + reserve); +      array.size = MathMin(size, array.capacity); +      ul -= (long)GetMicrosecondCount(); +      PrintFormat("Reallocation: [%d] -> [%d], done in %d µs",  +         temp, array.capacity, -ul); +   } +   else +   { +      array.size = size; +   } +   return array.size; +} + +``` + +An advantage of the DynArrayResize function compared to the built-in ArrayResize is in that that here we insert a debug printing for those situations when the internal capacity of the array is reallocated. + +Now we can take the standard example for the ArrayResize function from the MQL5 documentation and replace the built-in function calls with "self-made" analogs with the "Dyn" prefix. The modified result is presented in the script ArrayCapacity.mq5. + +``` +void OnStart() +{ +   ulong start = GetTickCount(); +   ulong now; +   int   count = 0; +    +   DynArray a; +    + // fast option with memory reservation +   Print("--- Test Fast: ArrayResize(arr,100000,100000)"); +    +   DynArrayResize(a, 100000, 100000); +    +   for(int i = 1; i <= 300000 && !IsStopped(); i++) +   { + // set the new size and reserve to 100000 elements +      DynArrayResize(a, i, 100000); + // on "round" iterations, show the size of the array and the elapsed time +      if(DynArraySize(a) % 100000 == 0) +      { +         now = GetTickCount(); +         count++; +         PrintFormat("%d. ArraySize(arr)=%d Time=%d ms",  +            count, DynArraySize(a), (now - start)); +         start = now; +      } +   } +   DynArrayFree(a); +    + // now this is a slow option without redundancy (with less redundancy) +   count = 0; +   start = GetTickCount(); +   Print("---- Test Slow: ArrayResize(slow,100000)"); +    +   DynArrayResize(a, 100000, 100000); +    +   for(int i = 1; i <= 300000 && !IsStopped(); i++) +   { + // set new size but with 100 times smaller margin: 1000 +      DynArrayResize(a, i, 1000); + // on "round" iterations, show the size of the array and the elapsed time +      if(DynArraySize(a) % 100000 == 0) +      { +         now = GetTickCount(); +         count++; +         PrintFormat("%d. ArraySize(arr)=%d Time=%d ms",  +            count, DynArraySize(a), (now - start)); +         start = now; +      } +   } +} + +``` + +The only significant difference is the following: in the slow version, the call ArrayResize(a, i) is replaced by a more moderate one DynArrayResize(a, i, 1000), that is, the redistribution is requested not at every iteration, but at every 1000th (otherwise the log will be overfilled with messages). + +After running the script, we will see the following timing in the log (absolute time intervals depend on your computer, but we are interested in the difference between performance variants with and without the reserve): + +``` +--- Test Fast: ArrayResize(arr,100000,100000) +Reallocation: [0] -> [200000], done in 17 µs +1. ArraySize(arr)=100000 Time=0 ms +2. ArraySize(arr)=200000 Time=0 ms +Reallocation: [200000] -> [300001], done in 2296 µs +3. ArraySize(arr)=300000 Time=0 ms +---- Test Slow: ArrayResize(slow,100000) +Reallocation: [0] -> [200000], done in 21 µs +1. ArraySize(arr)=100000 Time=0 ms +2. ArraySize(arr)=200000 Time=0 ms +Reallocation: [200000] -> [201001], done in 1838 µs +Reallocation: [201001] -> [202002], done in 1994 µs +Reallocation: [202002] -> [203003], done in 1677 µs +Reallocation: [203003] -> [204004], done in 1983 µs +Reallocation: [204004] -> [205005], done in 1637 µs +... +Reallocation: [295095] -> [296096], done in 2921 µs +Reallocation: [296096] -> [297097], done in 2189 µs +Reallocation: [297097] -> [298098], done in 2152 µs +Reallocation: [298098] -> [299099], done in 2767 µs +Reallocation: [299099] -> [300100], done in 2115 µs +3. ArraySize(arr)=300000 Time=219 ms + +``` + +The time gain is significant. In addition, we see at which iterations and how the real capacity of the array (reserve) is changed. + +void ArrayFree(void &array[]) + +The function releases all the memory of the passed dynamic array (including the possible reserve set using the third parameter of the function ArrayResize) and sets the size of its first dimension to zero. + +In theory, arrays in MQL5 release memory automatically when the execution of the algorithm in the current block ends. It doesn't matter if an array is defined locally (within functions) or globally, whether it is fixed or dynamic, as the system will free the memory itself in any case, without requiring explicit actions from the programmer. + +Thus, it is not necessary to call this function. However, there are situations when an array is used in an algorithm to re-fill with something from scratch, i.e., it needs to be freed before each filling. Then this feature might come in handy. + +Keep in mind that if the array elements contain pointers to dynamically allocated objects, the function does not delete them: the programmer must call delete for them (see below). + +Let's test the functions discussed above: ArrayIsDynamic, ArrayResize, ArrayFree. + +In the ArrayDynamic.mq5 script, the ArrayExtend function is written, which increases the size of the dynamic array by 1 and writes the passed value to the new element. + +``` +template +void ArrayExtend(T &array[], const T value) +{ +   if(ArrayIsDynamic(array)) +   { +      const int n = ArraySize(array); +      ArrayResize(array, n + 1); +      array[n] = (T)value; +   } +} + +``` + +The ArrayIsDynamic function is used to make sure that the array is only updated if it is dynamic. This is done in a conditional statement. The ArrayResize function allows you to change the size of the array, and the ArraySize function is used to find out the current size (it will be discussed in the next section). + +In the main function of the script, we will apply ArrayExtend for arrays of different categories: dynamic and fixed. + +``` +void OnStart() +{ +   int dynamic[]; +   int fixed[10] = {}; // padding with zeros +    +   PRT(ArrayResize(fixed, 0)); // warning: not applicable for fixed array +    +   for(int i = 0; i < 10; ++i) +   { +      ArrayExtend(dynamic, (i + 1) * (i + 1)); +      ArrayExtend(fixed, (i + 1) * (i + 1)); +   } +    +   Print("Filled"); +   ArrayPrint(dynamic); +   ArrayPrint(fixed); +    +   ArrayFree(dynamic); +   ArrayFree(fixed); // warning: not applicable for fixed array +    +   Print("Free Up"); +   ArrayPrint(dynamic); // outputs nothing +   ArrayPrint(fixed); +   ... +} + +``` + +In the code lines calling the functions that cannot be used for fixed arrays, the compiler generates a "cannot be used for static allocated array" warning. It is important to note that there are no such warnings inside the ArrayExtend function because an array of any category can be passed to the function. That is why we check this using ArrayIsDynamic. + +After a loop in OnStart, the dynamic array will expand to 10 and get the elements equal to the squared indices. The fixed array will remain filled with zeros and will not change size. + +Freeing a fixed array with ArrayFree will have no effect, and the dynamic array will actually be deleted. In this case, the last attempt to print it will not produce any lines in the log. + +Let's look at the script execution result. + +``` +   ArrayResize(fixed,0)=0 +   Filled    +     1   4   9  16  25  36  49  64  81 100 +   0 0 0 0 0 0 0 0 0 0 +   Free Up +   0 0 0 0 0 0 0 0 0 0 + +``` + +Of particular interest are dynamic arrays with pointers to objects. Let's define a simple dummy class Dummy and create an array of pointers to such objects. + +``` +class Dummy +{ +}; +  +void OnStart() +{ +   ... +   Dummy *dummies[] = {}; +   ArrayExtend(dummies, new Dummy()); +   ArrayFree(dummies); +} + +``` + +After extending the dummy array with a new pointer, we free it with ArrayFree, but there are entries in the terminal log indicating that the object was left in memory. + +``` +1 undeleted objects left +1 object of type Dummy left +24 bytes of leaked memory + +``` + +The fact is that the function manages only the memory that is allocated for the array. In this case, this memory held one pointer, but what it points to does not belong to the array. In other words, if the array contains pointers to "external" objects, then you need to take care of them yourself. For example: + +``` +for(int i = 0; i < ArraySize(dummies); ++i) +{ +   delete dummies[i]; +} + +``` + +This deletion must be started before calling ArrayFree. + +To shorten the entry, you can use the following macros (loop over elements, call delete for each of them): + +``` +#define FORALL(A) for(int _iterator_ = 0; _iterator_ < ArraySize(A); ++_iterator_) +#define FREE(P) { if(CheckPointer(P) == POINTER_DYNAMIC) delete (P); } +#define CALLALL(A, CALL) FORALL(A) { CALL(A[_iterator_]) } + +``` + +Then deletion of pointers is simplified to the following notation: + +``` +   ... +   CALLALL(dummies, FREE); +   ArrayFree(dummies); + +``` + +As an alternative solution, you can use a pointer wrapper class like AutoPtr, which we discussed in the section [Object type templates](/en/book/oop/templates/templates_objects). Then the array should be declared with the type AutoPtr. Since the array will store wrapper objects, not pointers, when the array is cleared, the destructors for each "wrapper" will be automatically called, and the pointer memory will in turn be freed from them. diff --git a/skills/mql5/references/book/03-common/0156-common-arrays-arrays-metrics.md b/skills/mql5/references/book/03-common/0156-common-arrays-arrays-metrics.md new file mode 100644 index 0000000..2091d84 --- /dev/null +++ b/skills/mql5/references/book/03-common/0156-common-arrays-arrays-metrics.md @@ -0,0 +1,81 @@ +# Array measurement + +One of the main characteristics of an array is its size, that is, the total number of elements in it. It is important to note that for multidimensional arrays, the size is the product of the lengths of all its dimensions. + +For fixed arrays, you can calculate their size at compile stage using the [sizeof](/en/book/basis/expressions/operators_sizeof_typename) operator-based language construct: + +``` +sizeof(array) / sizeof(type) + +``` + +where array is an identifier, and type is the array type. + +For example, if an array is defined in the code fixed: + +``` +int fixed[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; + +``` + +then its size is: + +``` +int n = sizeof(fixed) / sizeof(int); // 8 + +``` + +For dynamic arrays, this rule does not work, since the sizeof operator always generates the same size of the internal dynamic array object: 52 bytes. + +Note that in functions, all array parameters are represented internally as dynamic array wrapper objects. This is done so that an array with any method of memory allocation, including a fixed one, can be passed to the function. That's why sizeof(array) will return 52 for the parameter array, even if a fixed size array was passed through it. + +  + +The presence of "wrappers" affects only sizeof. The ArrayIsDynamic function always correctly determines the category of the actual argument passed through the parameter array. + +To get the size of any array at the stage of program execution, use the ArraySize function. + +int ArraySize(const void &array[]) + +The function returns the total number of elements in the array. The dimension and type of the array can be any. For a one-dimensional array, the function call is similar to ArrayRange(array, 0) (see below). + +If the array was distributed with a reserve (the third parameter of the [ArrayResize](/en/book/common/arrays/arrays_dynamic) function), its value is not taken into account. + +Until memory is allocated for the dynamic array using ArrayResize, the ArraySize function will return 0. Also, the size becomes zero after calling [ArrayFree](/en/book/common/arrays/arrays_dynamic) for the array. + +int ArrayRange(const void &array[], int dimension) + +The ArrayRange function returns the number of elements in the specified array dimension. The dimension and type of the array can be any. Parameter dimension must be between 0 and the number of array dimensions minus 1. Index 0 corresponds to the first dimension, index 1 to the second, and so on. + +Product of all values of ArrayRange(array, i) with i running over all dimensions gives ArraySize(array). + +Let's see the examples of the functions described above (see file ArraySize.mq5). + +``` +void OnStart() +{ +   int dynamic[]; +   int fixed[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; +    +   PRT(sizeof(fixed) / sizeof(int));   // 8 +   PRT(ArraySize(fixed));              // 8 +    +   ArrayResize(dynamic, 10); +    +   PRT(sizeof(dynamic) / sizeof(int)); // 13 (incorrect) +   PRT(ArraySize(dynamic));            // 10 +    +   PRT(ArrayRange(fixed, 0));          // 2 +   PRT(ArrayRange(fixed, 1));          // 4 +    +   PRT(ArrayRange(dynamic, 0));        // 10 +   PRT(ArrayRange(dynamic, 1));        // 0 +   int size = 1; +   for(int i = 0; i < 2; ++i) +   { +      size *= ArrayRange(fixed, i); +   } +   PRT(size == ArraySize(fixed));      // true +} + +``` diff --git a/skills/mql5/references/book/03-common/0157-common-arrays-arrays-init-fill.md b/skills/mql5/references/book/03-common/0157-common-arrays-arrays-init-fill.md new file mode 100644 index 0000000..8c42875 --- /dev/null +++ b/skills/mql5/references/book/03-common/0157-common-arrays-arrays-init-fill.md @@ -0,0 +1,91 @@ +# Initializing and populating arrays + +Describing an array with an initialization list is possible only for arrays of a fixed size. Dynamic arrays can be populated only after allocating memory for them by the function [ArrayResize](/en/book/common/arrays/arrays_dynamic). They are populated using the ArrayInitialize or ArrayFill functions. They are also useful in a program when you want to bulk-replace values in fixed arrays or time series. + +Examples of using the functions are given after their description. + +int ArrayInitialize(type &array[], type value) + +The function sets all array elements to the specified value. Only arrays of built-in numeric types are supported (char, uchar, short, ushort, int, uint, long, ulong, bool, color, datetime, float, double). String, structure and pointer arrays cannot be filled in this way: they will need to implement their own initialization functions. An array can be multidimensional. + +The function returns the number of elements. + +If the dynamic array is allocated with a reserve (the third parameter of the ArrayResize function), then the reserve is not initialized. + +If, after the array is initialized, its size is increased using ArrayResize, the added elements will not be automatically set to value. They can be populated using the ArrayFill function. + +void ArrayFill(type &array[], int start, int count, type value) + +The function fills a numeric array or part of it with a specified value. Part of the array is given by parameters start and count, which denote the initial number of the element and the number of elements to be filled, respectively. + +It does not matter to the function whether the numbering order of the array elements is set [like in timeseries](/en/book/common/arrays/arrays_as_series) or not: this property is ignored. In other words, the elements of an array are always counted from its beginning to its end. + +For a multidimensional array, the start parameter can be obtained by converting the coordinates in all dimensions into a through index for an equivalent one-dimensional array. So, for a two-dimensional array, the elements with the 0th index in the first dimension are located in memory first, then there will be the elements with the index 1 in the first dimension, and so on. The formula to calculate start is as follows: + +``` +start = D1 * N2 + D2 + +``` + +where D1 and D2 are the indexes for the first and second dimensions, respectively, N2 is the number of elements for the second dimension. D2 changes from 0 to (N2-1), D1 changes from 0 to (N1-1). For example, in an array array[3][4] the element with indexes [1][3] is the seventh one in a row, and therefore the call ArrayFill(array, 7, 2, ...) will fill two elements:array[1][3] and following after him array[2][0]. On the diagram, this can be depicted as follows (each cell contains a through index of the element): + +``` +      [][0]  [][1]  [][2]  [][3] +[0][]    0      1      2      3 +[1][]    4      5      6      7 +[2][]    8      9     10     11 + +``` + +The ArrayFill.mq5 script provides examples of using the aforementioned functions. + +``` +void OnStart() +{ +   int dynamic[]; +   int fixed[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; +    +   PRT(ArrayInitialize(fixed, -1)); +   ArrayPrint(fixed); +   ArrayFill(fixed, 3, 4, +1); +   ArrayPrint(fixed); +    +   PRT(ArrayResize(dynamic, 10, 50)); +   PRT(ArrayInitialize(dynamic, 0)); +   ArrayPrint(dynamic); +   PRT(ArrayResize(dynamic, 50)); +   ArrayPrint(dynamic); +   ArrayFill(dynamic, 10, 40, 0); +   ArrayPrint(dynamic); +} + +``` + +Here's what a possible result looks like (random data in uninitialized elements of a dynamic array will be different): + +``` +ArrayInitialize(fixed,-1)=8 +    [,0][,1][,2][,3] +[0,]  -1  -1  -1  -1 +[1,]  -1  -1  -1  -1 +    [,0][,1][,2][,3] +[0,]  -1  -1  -1   1 +[1,]   1   1   1  -1 +ArrayResize(dynamic,10,50)=10 +ArrayInitialize(dynamic,0)=10 +0 0 0 0 0 0 0 0 0 0 +ArrayResize(dynamic,50)=50 +[ 0]           0           0           0           0           0 +               0           0           0           0           0 +[10] -1402885947  -727144693   699739629   172950740 -1326090126 +           47384           0           0     4194184           0 +[20]           2           0           2           0           0 +               0           0  1765933056  2084602885 -1956758056 +[30]    73910037 -1937061701          56           0          56 +               0     1048601  1979187200       10851           0 +[40]           0           0           0  -685178880 -1720475236 +       782716519 -1462194191  1434596297   415166825 -1944066819 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +``` diff --git a/skills/mql5/references/book/03-common/0158-common-arrays-arrays-edit.md b/skills/mql5/references/book/03-common/0158-common-arrays-arrays-edit.md new file mode 100644 index 0000000..5552585 --- /dev/null +++ b/skills/mql5/references/book/03-common/0158-common-arrays-arrays-edit.md @@ -0,0 +1,536 @@ +# Copying and editing arrays + +In this section, we'll learn how to use built-in functions to insert and remove array elements, change their order, and copy entire arrays. + +bool ArrayInsert(void &target[], const void &source[], uint to, uint from = 0, uint count = WHOLE_ARRAY) + +The function inserts the specified number of elements from the source array 'source' into the destination target array. A position for insertion into the target array is set by the index in the to parameter. The starting index of the element at which to start copying from the source array is given by the index from. The WHOLE_ARRAY constant ((uint)-1) in the parameter count specifies the transfer of all elements of the source array. + +All indexes and counts are relative to the first dimension of the arrays. In other words, for multidimensional arrays, the insertion is performed not by individual elements, but by the entire configuration described by the "higher" dimensions. For example, for a two-dimensional array, the value 1 in the parameter count means inserting a vector of length equal to the second dimension (see the example). + +Due to this, the target array and the source array must have the same configurations. Otherwise, an error will occur and copying will fail. For one-dimensional arrays, this is not a limitation, but for multidimensional arrays, it is necessary to observe the equality of sizes in dimensions above the first one. In particular, elements from the array [][4] cannot be inserted into the array [][5] and vice versa. + +The function is applicable only for arrays of fixed or dynamic size. Editing timeseries (arrays with [time series](/en/book/applications/timeseries)) cannot be performed with this function. It is prohibited to specify in the parameters target and source the same array. + +When inserted into a fixed array, new elements shift existing elements to the right and displace count of the rightmost elements to the outside of the array. The to parameter must have a value between 0 and the size of the array minus 1. + +When inserted into a dynamic array, the old elements are also shifted to the right, but they do not disappear, because the array itself expands by count elements. The to parameter must have a value between 0 and the size of the array. If it is equal to the size of the array, new elements are added to the end of the array. + +The specified elements are copied from one array to another, i.e., they remain unchanged in the original array, and their "doubles" in the new array become independent instances that are not related to the "originals" in any way. + +The function returns true if successful or false in case of error. + +Let's consider some examples (ArrayInsert.mq5). The OnStart function provides descriptions of several arrays of different configurations, both fixed and dynamic. + +``` +#define PRTS(A) Print(#A, "=", (string)(A) + " / status:" + (string)GetLastError()) +  +void OnStart() +{ +   int dynamic[]; +   int dynamic2Dx5[][5]; +   int dynamic2Dx4[][4]; +   int fixed[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; +   int insert[] = {10, 11, 12}; +   int array[1] = {100}; +   ... + +``` + +To begin with, for convenience, a macro is introduced that displays the error code (obtained through the function [GetLastError](/en/book/common/environment/env_last_error)) immediately after calling the instruction under test — PRTS. This is a slightly modified version of the familiar PRT macro. + +Attempts to copy elements between arrays of different configurations end with error 4006 (ERR_INVALID_ARRAY). + +``` +   // you can't mix 1D and 2D arrays +   PRTS(ArrayInsert(dynamic, fixed, 0)); // false:4006, ERR_INVALID_ARRAY +   ArrayPrint(dynamic); // empty +   // you can't mix 2D arrays of different configurations by the second dimension +   PRTS(ArrayInsert(dynamic2Dx5, fixed, 0)); // false:4006, ERR_INVALID_ARRAY +   ArrayPrint(dynamic2Dx5); // empty +   // even if both arrays are fixed (or both are dynamic), +   // size by "higher" dimensions must match +   PRTS(ArrayInsert(fixed, insert, 0)); // false:4006, ERR_INVALID_ARRAY +   ArrayPrint(fixed); // not changed    +   ... + +``` + +The target index must be within the array. + +``` +   // target index 10 is out of the range or the array 'insert', +   // could be 0, 1, 2, because its size = 3 +   PRTS(ArrayInsert(insert, array, 10)); // false:5052, ERR_SMALL_ARRAY +   ArrayPrint(insert); // not changed    +   ... + +``` + +The following are successful array modifications: + +``` +   // copy second row from 'fixed', 'dynamic2Dx4' is allocated +   PRTS(ArrayInsert(dynamic2Dx4, fixed, 0, 1, 1)); // true +   ArrayPrint(dynamic2Dx4); +   // both rows from 'fixed' are added to the end of 'dynamic2Dx4', it expands +   PRTS(ArrayInsert(dynamic2Dx4, fixed, 1)); // true +   ArrayPrint(dynamic2Dx4); +   // memory is allocated for 'dynamic' for all elements 'insert' +   PRTS(ArrayInsert(dynamic, insert, 0)); // true +   ArrayPrint(dynamic); +   // 'dynamic' expands by 1 element +   PRTS(ArrayInsert(dynamic, array, 1)); // true +   ArrayPrint(dynamic); +   // new element will push the last one out of 'insert' +   PRTS(ArrayInsert(insert, array, 1)); // true +   ArrayPrint(insert); +} + +``` + +Here's what will appear in the log: + +``` +ArrayInsert(dynamic2Dx4,fixed,0,1,1)=true +    [,0][,1][,2][,3] +[0,]   5   6   7   8 +ArrayInsert(dynamic2Dx4,fixed,1)=true +    [,0][,1][,2][,3] +[0,]   5   6   7   8 +[1,]   1   2   3   4 +[2,]   5   6   7   8 +ArrayInsert(dynamic,insert,0)=true +10 11 12 +ArrayInsert(dynamic,array,1)=true + 10 100  11  12 +ArrayInsert(insert,array,1)=true + 10 100  11 +  + +``` + +bool ArrayCopy(void &target[], const void &source[], int to = 0, int from = 0, int count = WHOLE_ARRAY) + +The function copies part or all of the source array to the target array. The place in the target array where the elements are written is specified by the index in the to parameter. The starting index of the element from which to start copying from the source array is given by the from index. The WHOLE_ARRAY constant (-1) in the count parameter specifies the transfer of all elements of the source array. If count is less than zero or greater than the number of elements remaining from the from position to the end of the source array, the entire remainder of the array is copied. + +Unlike the ArrayInsert function, the ArrayCopy function does not shift the existing elements of the receiving array but writes new elements to the specified positions over the old ones. + +All indexes and the number of elements are set taking into account the continuous numbering of elements, regardless of the number of dimensions in the arrays and their configuration. In other words, elements can be copied from multidimensional arrays to one-dimensional arrays and vice versa, or between multidimensional arrays with different sizes according to the "higher" dimensions (see the example). + +The function works with fixed and dynamic arrays, as well as time series arrays designated as [indicator buffers](/en/book/applications/indicators_make/indicators_buffers_plots). + +It is permitted to copy elements from an array to itself. But if the target and source areas overlap, you need to keep in mind that the iteration is done from left to right. + +A dynamic destination array is automatically expanded as needed. Fixed arrays retain their dimensions, and what is copied must fit in the array, otherwise an error will occur. + +Arrays of built-in types and arrays of structures with simple type fields are supported. For numeric types, the function will try to convert the data if the source and destination types differ. A string array can only be copied to a string array. Class objects are not allowed, but pointers to objects can be copied. + +The function returns the number of elements copied (0 on error). + +In the script ArrayCopy.mq5 there are several examples of using the function. + +``` +class Dummy +{ +   int x; +}; +    +void OnStart() +{ +   Dummy objects1[5], objects2[5]; + // error: structures or classes with objects are not allowed +   PRTS(ArrayCopy(objects1, objects2)); +   ... + +``` + +Arrays with objects generate a compilation error stating that "structures or classes containing objects are not allowed", but pointers can be copied. + +``` +   Dummy *pointers1[5], *pointers2[5]; +   for(int i = 0; i < 5; ++i) +   { +      pointers1[i] = &objects1[i]; +   } +   PRTS(ArrayCopy(pointers2, pointers1)); // 5 / status:0 +   for(int i = 0; i < 5; ++i) +   { +      Print(i, " ", pointers1[i], " ", pointers2[i]); +   } + // it outputs some pairwise identical object descriptors +   /* +   0 1048576 1048576 +   1 2097152 2097152 +   2 3145728 3145728 +   3 4194304 4194304 +   4 5242880 5242880 +   */ + +``` + +Arrays of structures with fields of simple types are also copied without problems. + +``` +struct Simple +{ +   int x; +}; +    +void OnStart() +{ +   ... +   Simple s1[3] = {{123}, {456}, {789}}, s2[]; +   PRTS(ArrayCopy(s2, s1)); // 3 / status:0 +   ArrayPrint(s2); +   /* +       [x] +   [0] 123 +   [1] 456 +   [2] 789 +   */ +   ... + +``` + +To further demonstrate how to work with arrays of different types and configurations, the following arrays are defined (including fixed, dynamic, and arrays with a different number of dimensions): + +``` +   int dynamic[]; +   int dynamic2Dx5[][5]; +   int dynamic2Dx4[][4]; +   int fixed[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; +   int insert[] = {10, 11, 12}; +   double array[1] = {M_PI}; +   string texts[]; +   string message[1] = {"ok"}; +   ... + +``` + +When copying one element from the fixed array from position 1 (number 2), a whole row of 4 elements is allocated in the receiving dynamic array dynamic2Dx4, and since only 1 element is copied, the remaining three will contain random "garbage" (highlighted in yellow). + +``` +   PRTS(ArrayCopy(dynamic2Dx4, fixed, 0, 1, 1)); // 1 / status:0 +   ArrayPrint(dynamic2Dx4); +   /* +       [,0][,1][,2][,3] +   [0,]   2   1   2   3 +   */ +   ... + +``` + +Next, we copy all the elements from the fixed array, starting from the third one, into the same array dynamic2Dx4, but starting from position 1. Since 5 elements are copied (the total number in the array fixed is 8 minus the initial position 3), and they are placed at index 1, in total, 1 + 5 will be occupied in the receiving array, for a total of 6 elements. And since the array dynamic2Dx4 has 4 elements in each row (in the second dimension), it is possible to allocate memory for it only for the number of elements that is a multiple of 4, i.e., 2 more elements will be distributed, in which random data will remain. + +``` +   PRTS(ArrayCopy(dynamic2Dx4, fixed, 1, 3)); // 5 / status:0 +   ArrayPrint(dynamic2Dx4); +   /* +       [,0][,1][,2][,3] +   [0,]   2   4   5   6 +   [1,]   7   8   3   4 +   */ + +``` + +When copying a multidimensional array to a one-dimensional array, the elements will be presented in a "flat" form. + +``` +   PRTS(ArrayCopy(dynamic, fixed)); // 8 / status:0 +   ArrayPrint(dynamic); +   /* +   1 2 3 4 5 6 7 8 +   */ + +``` + +When copying a one-dimensional array to a multidimensional one, the elements are "expanded" according to the dimensions of the receiving array. + +``` +   PRTS(ArrayCopy(dynamic2Dx5, insert)); // 3 / status:0 +   ArrayPrint(dynamic2Dx5); +   /* +       [,0][,1][,2][,3][,4] +   [0,]  10  11  12   4   5 +   */ + +``` + +In this case, 3 elements were copied and they fit into one row which is 5 elements long (according to the configuration of the receiving array). The memory for the remaining two elements of the series was allocated, but not filled (contains "garbage"). + +We can overwrite the array dynamic2Dx5 from another source, including from a multidimensional array of a different configuration. Since two rows of 5 elements each were allocated in the receiving array, and 2 rows of 4 elements each were allocated in the source array, 2 additional elements were left unfilled. + +``` +   PRTS(ArrayCopy(dynamic2Dx5, fixed)); // 8 / status:0 +   ArrayPrint(dynamic2Dx5); +   /* +       [,0][,1][,2][,3][,4] +   [0,]   1   2   3   4   5 +   [1,]   6   7   8   0   0 +   */ + +``` + +By using ArrayCopy it is possible to change elements in fixed receiver arrays. + +``` +   PRTS(ArrayCopy(fixed, insert)); // 3 / status:0 +   ArrayPrint(fixed); +   /* +       [,0][,1][,2][,3] +   [0,]  10  11  12   4 +   [1,]   5   6   7   8 +   */ + +``` + +Here we have overwritten the first three elements of the array fixed. And then let's overwrite the last 3. + +``` +   PRTS(ArrayCopy(fixed, insert, 5)); // 3 / status:0 +   ArrayPrint(fixed); +   /* +       [,0][,1][,2][,3] +   [0,]  10  11  12   4 +   [1,]   5  10  11  12 +   */ + +``` + +Copying to a position equal to the length of the fixed array will not work (the dynamic destination array would expand in this case). + +``` +   PRTS(ArrayCopy(fixed, insert, 8)); // 4006, ERR_INVALID_ARRAY +   ArrayPrint(fixed); // no changes + +``` + +String arrays combined with arrays of other types will throw an error: + +``` +   PRTS(ArrayCopy(texts, insert)); // 5050, ERR_INCOMPATIBLE_ARRAYS +   ArrayPrint(texts); // empty + +``` + +But between string arrays, copying is possible: + +``` +   PRTS(ArrayCopy(texts, message)); +   ArrayPrint(texts); // "ok" + +``` + +Arrays of different numeric types are copied with the necessary conversion. + +``` +   PRTS(ArrayCopy(insert, array, 1)); // 1 / status:0 +   ArrayPrint(insert); // 10  3 12 + +``` + +Here we have written the number Pi in an integer array, and therefore received the value 3 (it replaced 11). + +bool ArrayRemove(void &array[], uint start, uint count = WHOLE_ARRAY) + +The function removes the specified number of elements from the array starting from the index start. An array can be multidimensional and have any built-in or structure type with fields of built-in types, with the exception of strings. + +The index start and quantity count refer to the first dimension of the arrays. In other words, for multidimensional arrays, deletion is performed not by individual elements, but by the entire configuration described by "higher" dimensions. For example, for a two-dimensional array, the value 1 in the parameter count means deleting a whole series of length equal to the second dimension (see the example). + +The value start must be between 0 and the size of the first dimension minus 1. + +The function cannot be applied to arrays with time series (built-in [timeseries](/en/book/applications/timeseries) or [indicator buffers](/en/book/applications/indicators_make/indicators_setindexbuffer)). + +To test the function, we prepared the script ArrayRemove.mq5. In particular, it defines 2 structures: + +``` +struct Simple +{ +   int x; +}; +    +struct NotSoSimple +{ +   int x; +   string s; // a field of type string causes the compiler to make an implicit destructor +}; + +``` + +Arrays with a simple structure can be processed by the function ArrayRemove successfully, while arrays of objects with destructors (even with implicit ones, as in NotSoSimple) cause an error: + +``` +void OnStart() +{ +   Simple structs1[10]; +   PRTS(ArrayRemove(structs1, 0, 5)); // true / status:0 +    +   NotSoSimple structs2[10]; +   PRTS(ArrayRemove(structs2, 0, 5)); // false / status:4005, +                                      // ERR_STRUCT_WITHOBJECTS_ORCLASS +   ... + +``` + +Next, arrays of various configurations are defined and initialized. + +``` +   int dynamic[]; +   int dynamic2Dx4[][4]; +   int fixed[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; +    +   // make 2 copies +   ArrayCopy(dynamic, fixed); +   ArrayCopy(dynamic2Dx4, fixed); +    +   // show initial data +   ArrayPrint(dynamic); +   /* +   1 2 3 4 5 6 7 8 +   */ +   ArrayPrint(dynamic2Dx4); +   /* +       [,0][,1][,2][,3] +   [0,]   1   2   3   4 +   [1,]   5   6   7   8 +   */ + +``` + +When deleting from a fixed array, all elements after the fragment being removed are shifted to the left. It is important that the size of the array does not change, and therefore copies of the shifted elements appear in duplicate. + +``` +   PRTS(ArrayRemove(fixed, 0, 1)); +   ArrayPrint(fixed); +   /* +   ArrayRemove(fixed,0,1)=true / status:0 +       [,0][,1][,2][,3] +   [0,]   5   6   7   8 +   [1,]   5   6   7   8 +   */ + +``` + +Here we removed one element of the first dimension of a two-dimensional array fixed by offset 0, that is, the initial row. The elements of the next row moved up and remained in the same row. + +If we perform the same operation with a dynamic array (identical in content to the array fixed), its size will be automatically reduced by the number of elements removed. + +``` +   PRTS(ArrayRemove(dynamic2Dx4, 0, 1)); +   ArrayPrint(dynamic2Dx4); +   /* +   ArrayRemove(dynamic2Dx4,0,1)=true / status:0 +       [,0][,1][,2][,3] +   [0,]   5   6   7   8 +   */ + +``` + +In a one-dimensional array, each element removed corresponds to a single value. For example, in the array dynamic, when removing three elements starting at index 2, we get the following result: + +``` +   PRTS(ArrayRemove(dynamic, 2, 3)); +   ArrayPrint(dynamic); +   /* +   ArrayRemove(dynamic,2,3)=true / status:0 +   1 2 6 7 8 +   */ + +``` + +The values 3, 4, 5 have been removed, the array size has been reduced by 3. + +bool ArrayReverse(void &array[], uint start = 0, uint count = WHOLE_ARRAY) + +The function reverses the order of the specified elements in the array. Elements to be reversed are determined by a starting position start and quantity count. If start = 0, and count = WHOLE_ARRAY, the entire array is accessed. + +Arrays of arbitrary dimensions and types are supported, both fixed and dynamic (including time series in [indicator buffers](/en/book/applications/indicators_make/indicators_setindexbuffer)). An array can contain objects, pointers, or structures. For multidimensional arrays, only the first dimension is reversed. + +The count value must be between 0 and the number of elements in the first dimension. Please note that count less than 2 will not give a noticeable effect, but it can be used to unify loops in algorithms. + +The function returns true if successful or false in case of error. + +The ArrayReverse.mq5 script can be used to test the function. At its beginning, a class is defined for generating objects stored in an array. The presence of strings and other "complex" fields is not a problem. + +``` +class Dummy +{ +   static int counter; +   int x; +   string s; // a field of type string causes the compiler to create an implicit destructor +public: +   Dummy() { x = counter++; } +}; +    +static int Dummy::counter; + +``` + +Objects are identified by a serial number (assigned at the time of creation). + +``` +void OnStart() +{ +   Dummy objects[5]; +   Print("Objects before reverse"); +   ArrayPrint(objects); +   /* +       [x]  [s] +   [0]   0 null +   [1]   1 null +   [2]   2 null +   [3]   3 null +   [4]   4 null +   */ + +``` + +After applying ArrayReverse we get the expected reverse order of the objects. + +``` +   PRTS(ArrayReverse(objects)); // true / status:0 +   Print("Objects after reverse"); +   ArrayPrint(objects); +   /* +       [x]  [s] +   [0]   4 null +   [1]   3 null +   [2]   2 null +   [3]   1 null +   [4]   0 null +   */ + +``` + +Next, numerical arrays of different configurations are prepared and unfolded with different parameters. + +``` +   int dynamic[]; +   int dynamic2Dx4[][4]; +   int fixed[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; +    +   ArrayCopy(dynamic, fixed); +   ArrayCopy(dynamic2Dx4, fixed); +    +   PRTS(ArrayReverse(fixed)); // true / status:0 +   ArrayPrint(fixed); +   /* +       [,0][,1][,2][,3] +   [0,]   5   6   7   8 +   [1,]   1   2   3   4 +   */ +    +   PRTS(ArrayReverse(dynamic, 4, 3)); // true / status:0 +   ArrayPrint(dynamic); +   /* +   1 2 3 4 7 6 5 8 +   */ +    +   PRTS(ArrayReverse(dynamic, 0, 1)); // does nothing (count = 1) +   PRTS(ArrayReverse(dynamic2Dx4, 2, 1)); // false / status:5052, ERR_SMALL_ARRAY +} + +``` + +In the latter case, the value start (2) exceeds the size in the first dimension, so an error occurs. diff --git a/skills/mql5/references/book/03-common/0159-common-arrays-arrays-move-swap.md b/skills/mql5/references/book/03-common/0159-common-arrays-arrays-move-swap.md new file mode 100644 index 0000000..b94ab73 --- /dev/null +++ b/skills/mql5/references/book/03-common/0159-common-arrays-arrays-move-swap.md @@ -0,0 +1,101 @@ +# Moving (swapping) arrays + +MQL5 provides the ability to swap the contents of two arrays in a resource-efficient way (without physical allocation of memory and copying data). In some other programming languages, a similar operation is supported not only for arrays, but also for other variables, and is called moving. + +bool ArraySwap(void &array1[], void &array2[]) + +The function swaps the contents of two dynamic arrays of the same type. Arrays of any type are supported. However, the function is not applicable to timeseries arrays and indicator buffers, as well as to any arrays with the const modifier. + +For multidimensional arrays, the number of elements in all dimensions except the first must match. + +The function returns true if successful or false in case of error. + +The main use of the function is to speed up the program by eliminating the physical copying of the array when it is passed to or returned from the function, and it is known that the source array is no longer needed. The fact is that swapping takes place almost instantly since the application data does not move in any way. Instead, there is an exchange of meta-data about arrays stored in service structures that describe dynamic arrays (and this takes only 52 bytes). + +Suppose there is a class intended for processing an array by certain algorithms. The same array can be subjected to different operations and therefore it makes sense to keep it as a class member. But then there is a question, how to transfer it to an object? In MQL5, methods (as well as functions in general) allow passing arrays only by reference. Putting aside all kinds of wrapper classes that contain an array and are passed by pointer, the only simple solution seems to be the following: to describe, for example, an array parameter in the class constructor and copy it to the internal array using ArrayCopy. But it is more efficient to use ArraySwap. + +``` +template +class Worker +{ +   T array[]; +    +public: +   Worker(T &source[]) +   { +      // ArrayCopy(array, source); // memory and time consuming  +      ArraySwap(source, array); +   } +   ... +}; + +``` + +Since the array array was empty before the swap, after the operation the array used as the source argument will become empty, while array will be filled with input data with little or no overhead. + +After the object of the class becomes the "owner" of the array, we can modify it with the required algorithms, for example, through a special method process, which takes the code of the requested algorithm as a parameter. It can be sorting, smoothing, mixing, adding noise and much more. But first, let's try to test the idea on a simple operation of array reversal by the function ArrayReverse (see file ArraySwapSimple.mq5). + +``` +   bool process(const int mode) +   { +      if(ArraySize(array) == 0) return false; +      switch(mode) +      { +      case -4: +         // example: shuffling +         break; +      case -3: +         // example: logarithm +         break; +      case -2: +         // example: adding noise +         break; +      case -1: +         ArrayReverse(array); +         break; +      ... +      } +      return true; +   } + +``` + +You can provide access to the results of work using two methods: element by element (by overloading the '[]' operator) or by an entire array (again we use ArraySwap in the corresponding method get, but you can also provide a method for copying through ArrayCopy). + +``` +   T operator[](int i) +   { +      return array[i]; +   } +    +   void get(T &result[]) +   { +      ArraySwap(array, result); +   } + +``` + +For the purpose of universality, the class is made template. This will allow adapting it in the future for arrays of arbitrary structures, but for now, you can check the inversion of a simple array of the type double: + +``` +void OnStart() +{ +   double data[]; +   ArrayResize(data, 3); +   data[0] = 1; +   data[1] = 2; +   data[2] = 3; +    +   PRT(ArraySize(data));        // 3 +   Worker simple(data); +   PRT(ArraySize(data));        // 0 +   simple.process(-1);  // reversing array +    +   double res[]; +   simple.get(res); +   ArrayPrint(res); // 3.00000 2.00000 1.00000 +} + +``` + +The task of sorting is more realistic, and for an array of structures, sorting by any field may be required. In the [next section](/en/book/common/arrays/arrays_compare_sort_search) we will study in detail the function ArraySort, which allows you to sort in ascending order an array of any built-in type, but not structures. There we will try to eliminate this "gap", leaving ArraySwap in action. diff --git a/skills/mql5/references/book/03-common/0160-common-arrays-arrays-compare-sort-search.md b/skills/mql5/references/book/03-common/0160-common-arrays-arrays-compare-sort-search.md new file mode 100644 index 0000000..9cb0c90 --- /dev/null +++ b/skills/mql5/references/book/03-common/0160-common-arrays-arrays-compare-sort-search.md @@ -0,0 +1,676 @@ +# Comparing, sorting, and searching in arrays + +The MQL5 API contains several functions that allow comparing and sorting arrays, as well as searching for the maximum, minimum, or any specific value in them. + +int ArrayCompare(const void &array1[], const void &array2[], int start1 = 0, int start2 = 0, int count = WHOLE_ARRAY) + +The function returns the result of comparing two arrays of built-in types or structures with fields of built-in types, excluding strings. Arrays of class objects are not supported. Also, you cannot compare arrays of structures that contain dynamic arrays, class objects, or pointers. + +By default, the comparison is performed for entire arrays but, if necessary, you can specify parts of arrays, for which there are parameters start1 (starting position in the first array), start2 (starting position in the second array), and count. + +Arrays can be fixed or dynamic, as well as multidimensional. During comparison, multidimensional arrays are represented as equivalent one-dimensional arrays (for example, for two-dimensional arrays, the elements of the second row follow the elements of the first, the elements of the third row follow the second, and so on). For this reason, the parameters start1, start2, and count for multidimensional arrays are specified through element numbering, and not an index along the first dimension. + +Using various start1 and start2 offsets you can compare different parts of the same array. + +Arrays are compared element by element until the first discrepancy is found or the end of one of the arrays is reached. The relationship between two elements (which are in the same positions in both arrays) depends on the type: for numbers, the operators '>', '<', '==' are used, and for strings, the [StringCompare](/en/book/common/strings/strings_comparison) function is used. Structures are compared byte by byte, which is equivalent to executing the following code for each pair of elements: + +``` +uchar bytes1[], bytes2[]; +StructToCharArray(array1[i], bytes1); +StructToCharArray(array2[i], bytes2); +int cmp = ArrayCompare(bytes1, bytes2); + +``` + +Based on the ratio of the first differing elements, the result of bulk comparison of the arrays array1 and array2 is obtained. If no differences are found, and the length of the arrays is equal, then the arrays are considered the same. If the length is different, then the longer array is considered greater. + +The function returns -1 if array1 is "less than" array2, +1 if array1 is "greater than" array2, and 0 if they are "equal". + +In case of an error, the result is -2. + +Let's look at some examples in the script ArrayCompare.mq5. + +Let's create a simple structure for filling the arrays to be compared. + +``` +struct Dummy +{ +   int x; +   int y; +    +   Dummy() +   { +      x = rand() / 10000; +      y = rand() / 5000; +   } +}; + +``` + +The class fields are filled with random numbers (each time the script is run, we will receive new values). + +In the OnStart function, we describe a small array of structures and compare successive elements with each other (as moving neighboring fragments of an array with the length of 1 element). + +``` +#define LIMIT 10 +  +void OnStart() +{ +   Dummy a1[LIMIT]; +   ArrayPrint(a1); +    +   // pairwise comparison of neighboring elements +   // -1: [i] < [i + 1] +   // +1: [i] > [i + 1] +   for(int i = 0; i < LIMIT - 1; ++i) +   { +      PRT(ArrayCompare(a1, a1, i, i + 1, 1)); +   } +   ... + +``` + +Below are the results for one of the array options (for the convenience of analysis, the column with the signs "greater than" (+1) / "less than" (-1) is added directly to the right of the contents of the array): + +``` +       [x] [y]   // result +   [0]   0   3   // -1 +   [1]   2   4   // +1 +   [2]   2   3   // +1 +   [3]   1   6   // +1 +   [4]   0   6   // -1 +   [5]   2   0   // +1 +   [6]   0   4   // -1 +   [7]   2   5   // +1 +   [8]   0   5   // -1 +   [9]   3   6 + +``` + +Comparing the two halves of the array to each other gives -1: + +``` + // compare first and second half +   PRT(ArrayCompare(a1, a1, 0, LIMIT / 2, LIMIT / 2)); // -1 + +``` + +Next, we will compare arrays of strings with predefined data. + +``` +   string s[] = {"abc", "456", "$"}; +   string s0[][3] = {{"abc", "456", "$"}}; +   string s1[][3] = {{"abc", "456", ""}}; +   string s2[][3] = {{"abc", "456"}}; // last element omitted: it is null +   string s3[][2] = {{"abc", "456"}}; +   string s4[][2] = {{"aBc", "456"}}; +    +   PRT(ArrayCompare(s0, s));  // s0 == s, 1D and 2D arrays contain the same data +   PRT(ArrayCompare(s0, s1)); // s0 > s1 since "$" > "" +   PRT(ArrayCompare(s1, s2)); // s1 > s2 since "" > null +   PRT(ArrayCompare(s2, s3)); // s2 > s3 due to different lengths: [3] > [2] +   PRT(ArrayCompare(s3, s4)); // s3 < s4 since "abc" < "aBc" + +``` + +Finally, let's check the ratio of array fragments: + +``` +   PRT(ArrayCompare(s0, s1, 1, 1, 1)); // second elements (with index 1) are equal  +   PRT(ArrayCompare(s1, s2, 0, 0, 2)); // the first two elements are equal + +``` + +bool ArraySort(void &array[]) + +The function sorts a numeric array (including possibly a multidimensional array) by the first dimension. The sorting order is ascending. To sort an array in descending order, apply the [ArrayReverse](/en/book/common/arrays/arrays_edit) function to the resulting array or process it in reverse order. + +The function does not support arrays of strings, structures, or classes. + +The function returns true if successful or false in case of error. + +If the "timeseries" property is set for an array, then the elements in it are indexed in the reverse order (see details in section [Array indexing direction as in timeseries](/en/book/common/arrays/arrays_as_series)), and this has an "external" reversal effect on the sorting order: when you process such an array directly, you will get descending values. At the physical level, the array is always sorted in ascending order, and that is how it is stored. + +In the script ArraySort.mq5 a 10 by 3, 2-dimensional array is generated and sorted using ArraySort: + +``` +#define LIMIT 10 +#define SUBLIMIT 3 +    +void OnStart() +{ +   // generating random data +   int array[][SUBLIMIT]; +   ArrayResize(array, LIMIT); +   for(int i = 0; i < LIMIT; ++i) +   { +      for(int j = 0; j < SUBLIMIT; ++j) +      { +         array[i][j] = rand(); +      } +   } +    +   Print("Before sort"); +   ArrayPrint(array);    // source array +    +   PRTS(ArraySort(array)); +    +   Print("After sort"); +   ArrayPrint(array);    // ordered array +   ... +} + +``` + +According to the log, the first column is sorted in ascending order (specific numbers will vary due to random generation): + +``` +Before sort +      [,0]  [,1]  [,2] +[0,]  8955  2836 20011 +[1,]  2860  6153 25032 +[2,] 16314  4036 20406 +[3,] 30366 10462 19364 +[4,] 27506  5527 21671 +[5,]  4207  7649 28701 +[6,]  4838   638 32392 +[7,] 29158 18824 13536 +[8,] 17869 23835 12323 +[9,] 18079  1310 29114 +ArraySort(array)=true / status:0 +After sort +      [,0]  [,1]  [,2] +[0,]  2860  6153 25032 +[1,]  4207  7649 28701 +[2,]  4838   638 32392 +[3,]  8955  2836 20011 +[4,] 16314  4036 20406 +[5,] 17869 23835 12323 +[6,] 18079  1310 29114 +[7,] 27506  5527 21671 +[8,] 29158 18824 13536 +[9,] 30366 10462 19364 + +``` + +The values in the following columns have moved synchronously with the "leading" values in the first column. In other words, the entire rows are permuted, despite the fact that only the first column is the sorting criterion. + +But what if you want to sort a two-dimensional array by a column other than the first one? You can write a special algorithm for that. One of the options is included in the file ArraySort.mq5 as a template function: + +``` +template +bool ArraySort(T &array[][], const int column) +{ +   if(!ArrayIsDynamic(array)) return false; +    +   if(column == 0) +   { +      return ArraySort(array); // standard function  +   } +    +   const int n = ArrayRange(array, 0); +   const int m = ArrayRange(array, 1); +    +   T temp[][2]; +    +   ArrayResize(temp, n); +   for(int i = 0; i < n; ++i) +   { +      temp[i][0] = array[i][column]; +      temp[i][1] = i; +   } +    +   if(!ArraySort(temp)) return false; +    +   ArrayResize(array, n * 2); +   for(int i = n; i < n * 2; ++i) +   { +      ArrayCopy(array, array, i * m, (int)(temp[i - n][1] + 0.1) * m, m); +      /* equivalent +      for(int j = 0; j < m; ++j) +      { +         array[i][j] = array[(int)(temp[i - n][1] + 0.1)][j]; +      } +      */ +   } +    +   return ArrayRemove(array, 0, n); +} + +``` + +The given function only works with dynamic arrays because the size of array is doubled to assemble intermediate results in the second half of the array, and finally, the first half (original) is removed with ArrayRemove. That is why the original test array in the OnStart function was distributed through ArrayResize. + +We encourage you to study the sorting principle on your own (or turn over a couple of pages). + +Something similar should be implemented for arrays with a large number of dimensions (for example, array[][][]). + +Now recall that in the previous section, we raised the issue of sorting an array of structures by an arbitrary field. As we know, the standard ArraySort function is not able to do this. Let's try to come up with a "bypass route". Let's take the class from the ArraySwapSimple.mq5 file from the previous section as a basis. Let's copy it to ArrayWorker.mq5 and add the required code. + +In the Worker::process method, we will provide a call to the auxiliary sorting method arrayStructSort, and the field to be sorted will be specified by number (how it can be done, we will describe below): + +``` +   ... +   bool process(const int mode) +   { +      ... +      switch(mode) +      { +      ... +      case -1: +         ArrayReverse(array); +         break; +      default: // sorting by field number 'mode' +         arrayStructSort(mode); +         break; +      } +      return true; +   } +    +private: +   bool arrayStructSort(const int field) +   { +      ... +   } + +``` + +Now it becomes clear why all the previous modes (values of the mode parameter) in the process method were negative: zero and positive values are reserved for sorting and correspond to the "column" number. + +The idea of sorting an array of structures is taken from sorting a two-dimensional array. We only need to somehow map a single structure to a one-dimensional array (representing a row of a two-dimensional array). To do this, firstly, you need to decide what type the array should be. + +Since the worker class is already a template, we will add one more parameter to the template so that the array type can be flexibly set. + +``` +template +class Worker +{ +   T array[]; +   ... + +``` + +Now, let's get back to [associations](/en/book/oop/structs_and_unions/unions), which allow you to overlay variables of different types on top of each other. Thus, we get the following tricky construction: + +``` +   union Overlay +   { +      T r; +      R d[sizeof(T) / sizeof(R)]; +   }; + +``` + +In this union, the type of the structure is combined with an array of type R, and its size is automatically calculated by the compiler based on the ratio of the sizes of two types, T and R. + +Now, inside the arrayStructSort method, we can partially duplicate the code of two-dimensional array sorting. + +``` +   bool arrayStructSort(const int field) +   { +      const int n = ArraySize(array); +       +      R temp[][2]; +      Overlay overlay; +       +      ArrayResize(temp, n); +      for(int i = 0; i < n; ++i) +      { +         overlay.r = array[i]; +         temp[i][0] = overlay.d[field]; +         temp[i][1] = i; +      } +      ... + +``` + +Instead of an array with the original structures, we prepare the temp[][2] array of type R, extend it to the number of records in array, and write the following in the loop: the "display" of the required field field from the structure at the 0th index of each row, and the original index of this element at the 1st index. + +The "display" is based on the fact that fields in structures are usually aligned in some way since they use standard types. Therefore, with a properly chosen R type, it is possible to provide full or partial hitting of fields in the array elements in the "overlay". + +For example, in the standard structure [MqlRates](/en/book/applications/timeseries/timeseries_mqlrates) the first 6 fields are 8 bytes in size, and therefore map correctly onto the array double or long (these are R template type candidates). + +``` +struct MqlRates  +{  +   datetime time;  +   double   open;  +   double   high;  +   double   low;  +   double   close;  +   long     tick_volume;  +   int      spread;  +   long     real_volume;  +}; + +``` + +With the last two fields, the situation is more complicated. If the field spread still can be reached using type int as R, then the field real_volume turns out to be at an offset that is not a multiple of its own size (due to the field type int, i.e. 4 bytes, before it). These are problems of a particular method. It can be improved, or another method can be invented. + +But let's go back to the sorting algorithm. After the array temp is populated, it can be sorted with the usual function ArraySort, and then the original indexes can be used to form a new array with the correct structure order. + +``` +      ... +      if(!ArraySort(temp)) return false; +      T result[]; +       +      ArrayResize(result, n); +      for(int i = 0; i < n; ++i) +      { +         result[i] = array[(int)(temp[i][1] + 0.1)]; +      } +       +      return ArraySwap(result, array); +   } + +``` + +Before exiting the function, we use ArraySwap again, in order to replace the contents of an intra-object array array in a resource-efficient way with something new and ordered, which is received in the local array result. + +Let's check the class worker in action: in the function OnStart let's define an array of structures MqlRates and ask the terminal for several thousand records. + +``` +#define LIMIT 5000 +  +void OnStart() +{ +   MqlRates rates[]; +   int n = CopyRates(_Symbol, _Period, 0, LIMIT, rates); +   ... + +``` + +The CopyRates function will be described in a [separate section](/en/book/applications/timeseries/timeseries_mqlrates). For now, it's enough for us to know that it fills the passed array rates with quotes of the symbol and timeframe of the current chart on which the script is running. The macro LIMIT specifies the number of requested bars: you need to make sure that this value is not greater than your terminal's setting for the number of bars in each window. + +To process the received data, we will create an object worker with types T=MqlRates and R=double: + +``` +Worker worker(rates); + +``` + +Sorting can be started with an instruction of the following form: + +``` +worker.process(offsetof(MqlRates, open) / sizeof(double)); + +``` + +Here we use the [offsetof](/en/book/oop/structs_and_unions/structs_pack_dll) operator to get the byte offset of the field open inside the structure. It is further divided by the size double and gives the correct "column" number for sorting by the open price. You can read the sorting result element by element, or get the entire array: + +``` +Print(worker[i].open); +... +worker.get(rates); +ArrayPrint(rates); + +``` + +Note that getting an array by the method get moves it out of the inner array array to the outer one (passed as an argument) with ArraySwap. So, after that the calls worker.process() are pointless: there is no more data in the object worker. + +To simplify the start of sorting by different fields, an auxiliary function sort has been implemented: + +``` +void sort(Worker &worker, const int offset, const string title) +{ +   Print(title); +   worker.process(offset); +   Print("First struct"); +   StructPrint(worker[0]); +   Print("Last struct"); +   StructPrint(worker[worker.size() - 1]); +} + +``` + +It outputs a header and the first and last elements of the sorted array to the log. With its help, testing in OnStart for three fields looks like this: + +``` +void OnStart() +{ +   ... +   Worker worker(rates); +   sort(worker, offsetof(MqlRates, open) / sizeof(double), "Sorting by open price..."); +   sort(worker, offsetof(MqlRates, tick_volume) / sizeof(double), "Sorting by tick volume..."); +   sort(worker, offsetof(MqlRates, time) / sizeof(double), "Sorting by time..."); +} + +``` + +Unfortunately, the standard function print does not support printing of single structures, and there is no built-in function StructPrint in MQL5. Therefore, we had to write it ourselves, based on ArrayPrint: in fact, it is enough to put the structure in an array of size 1. + +``` +template +void StructPrint(const S &s) +{ +   S temp[1]; +   temp[0] = s; +   ArrayPrint(temp); +} + +``` + +As a result of running the script, we can get something like the following (depending on the terminal settings, namely on which symbol/timeframe it is executed): + +``` +Sorting by open price... +First struct +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.07.21 10:30:00 1.17557 1.17584 1.17519 1.17561          1073        0             0 +Last struct +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.05.25 15:15:00 1.22641 1.22664 1.22592 1.22618           852        0             0 +Sorting by tick volume... +First struct +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.05.24 00:00:00 1.21776 1.21811 1.21764 1.21794            52       20             0 +Last struct +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.06.16 21:30:00 1.20436 1.20489 1.20149 1.20154          4817        0             0 +Sorting by time... +First struct +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.05.14 16:15:00 1.21305 1.21411 1.21289 1.21333           888        0             0 +Last struct +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.07.27 22:45:00 1.18197 1.18227 1.18191 1.18225           382        0             0 + +``` + +Here is the data for EURUSD,M15. + +The above implementation of sorting is potentially one of the fastest because it uses the built-in ArraySort. + +If, however, the difficulties with aligning the fields of the structure or the skepticism towards the very approach of "mapping" the structure into an array force us to abandon this method (and thus, the function ArraySort), the proven "do-it-yourself" method remains at our disposal. + +There are a large number of sorting algorithms that are easy to adapt to MQL5. One of the quick sorting options is presented in the file QuickSortStructT.mqh attached to the book. This is an improved version QuickSortT.mqh, which we used in the section [String comparison](/en/book/common/strings/strings_comparison). It has the method Compare of the template class QuickSortStructT which is made purely virtual and must be redefined in the descendant class to return an analog of the comparison operator '>' for the required type and its fields. For the user convenience, a macro has been created in the header file: + +``` +#define SORT_STRUCT(T, A, F)                                           \ +{                                                                    \ +   class InternalSort : public QuickSortStructT                   \ +   {                                                                 \ +      virtual bool Compare(const T &a, const T &b) override          \ +      {                                                              \ +         return a.##F > b.##F;                                       \ +      }                                                              \ +   } sort;                                                           \ +   sort.QuickSort(A);                                                \ +} + +``` + +Using it, to sort an array of structures by a given field, it is enough to write one instruction. For example: + +``` +   MqlRates rates[]; +   CopyRates(_Symbol, _Period, 0, 10000, rates); +   SORT_STRUCT(MqlRates, rates, high); + +``` + +Here the rates array of type MqlRates is sorted by the high price. + +int ArrayBsearch(const type &array[], type value) + +The function searches a given value in a numeric array. Arrays of all built-in numeric types are supported. The array must be sorted in ascending order by the first dimension, otherwise the result will be incorrect. + +The function returns the index of the matching element (if there are several, then the index of the first of them) or the index of the element closest in value (if there is no exact match), ti.e., it can be an element with either a larger or smaller value than the one being searched for. If the desired value is less than the first (minimum), then 0 is returned. If the searched value is greater than the last (maximum), its index is returned. + +The index depends on the direction of the numbering of the elements in the array: direct (from the beginning to the end) or reverse (from the end to the beginning). It can be recognized and changed using the functions described in the section [Array indexing direction as in timeseries](/en/book/common/arrays/arrays_as_series). + +If an error occurs, -1 is returned. + +For multidimensional arrays, the search is limited to the first dimension. + +In the script ArraySearch.mq5 one can find examples of using the function ArrayBsearch. + +``` +void OnStart() +{ +   int array[] = {1, 5, 11, 17, 23, 23, 37}; +     // indexes  0  1   2   3   4   5   6 +   int data[][2] = {{1, 3}, {3, 2}, {5, 10}, {14, 10}, {21, 8}}; +     // indexes     0       1       2         3         4 +   int empty[]; +   ... + +``` + +For three predefined arrays (one of them is empty), the following statements are executed: + +``` +   PRTS(ArrayBsearch(array, -1)); // 0 +   PRTS(ArrayBsearch(array, 11)); // 2 +   PRTS(ArrayBsearch(array, 12)); // 2 +   PRTS(ArrayBsearch(array, 15)); // 3 +   PRTS(ArrayBsearch(array, 23)); // 4 +   PRTS(ArrayBsearch(array, 50)); // 6 +    +   PRTS(ArrayBsearch(data, 7));   // 2 +   PRTS(ArrayBsearch(data, 9));   // 2 +   PRTS(ArrayBsearch(data, 10));  // 3 +   PRTS(ArrayBsearch(data, 11));  // 3 +   PRTS(ArrayBsearch(data, 14));  // 3 +    +   PRTS(ArrayBsearch(empty, 0));  // -1, 5053, ERR_ZEROSIZE_ARRAY +   ... + +``` + +Further, in the populateSortedArray helper function, the numbers array is filled with random values, and the array is constantly maintained in a sorted state using ArrayBsearch. + +``` +void populateSortedArray(const int limit) +{ +   double numbers[];  // array to fill + doubleelement[1];// new value to insert +    +   ArrayResize(numbers, 0, limit); // allocate memory beforehand +    +   for(int i = 0; i < limit; ++i) +   { +      // generate a random number +      element[0] = NormalizeDouble(rand() * 1.0 / 32767, 3); +      // find where its place in the array +      int cursor = ArrayBsearch(numbers, element[0]); +      if(cursor == -1) +      { +         if(_LastError == 5053) // empty array +         { +            ArrayInsert(numbers, element, 0); +         } +         else break; // error +      } +      else +      if(numbers[cursor] > element[0]) // insert at 'cursor' position  +      { +         ArrayInsert(numbers, element, cursor); +      } +      else // (numbers[cursor] <= value) // insert after 'cursor' +      { +         ArrayInsert(numbers, element, cursor + 1); +      } +   } +   ArrayPrint(numbers, 3); +} + +``` + +Each new value goes first into a one-element array element, because this way it's easier to insert it into the resulting array numbers using the function [ArrayInsert](/en/book/common/arrays/arrays_edit). + +ArrayBsearch allows you to determine where the new value should be inserted. + +The result of the function is displayed in the log: + +``` +void OnStart() +{ +   ... +   populateSortedArray(80); +   /* +    example (will be different on each run due to randomization) +   [ 0] 0.050 0.065 0.071 0.106 0.119 0.131 0.145 0.148 0.154 0.159 +        0.184 0.185 0.200 0.204 0.213 0.216 0.220 0.224 0.236 0.238 +   [20] 0.244 0.259 0.267 0.274 0.282 0.293 0.313 0.334 0.346 0.366 +        0.386 0.431 0.449 0.461 0.465 0.468 0.520 0.533 0.536 0.541 +   [40] 0.597 0.600 0.607 0.612 0.613 0.617 0.621 0.623 0.631 0.634 +        0.646 0.658 0.662 0.664 0.670 0.670 0.675 0.686 0.693 0.694 +   [60] 0.725 0.739 0.759 0.762 0.768 0.783 0.791 0.791 0.791 0.799 +        0.838 0.850 0.854 0.874 0.897 0.912 0.920 0.934 0.944 0.992 +   */ + +``` + +int ArrayMaximum(const type &array[], int start = 0, int count = WHOLE_ARRAY) + +int ArrayMinimum(const type &array[], int start = 0, int count = WHOLE_ARRAY) + +The functions ArrayMaximum and ArrayMinimum search a numeric array for the elements with the maximum and minimum values, respectively. The range of indexes for searching is set by start and count parameters: with default values, the entire array is searched. + +The function returns the position of the found element. + +If the "serial" property ("timeseries") is set for an array, the indexing of elements in it is carried out in the reverse order, and this affects the result of this function (see the example). Built-in functions for working with the "serial" property are discussed in the [next section](/en/book/common/arrays/arrays_as_series). More details about "serial" arrays will be discussed in the chapters on [timeseries](/en/book/applications/timeseries) and [indicators](/en/book/applications/indicators_make). + +In multidimensional arrays, the search is performed on the first dimension. + +If there are several identical elements in the array with a maximum or minimum value, the function will return the index of the first of them. + +An example of using functions is given in the file ArrayMaxMin.mq5. + +``` +#define LIMIT 10 +    +void OnStart() +{ +   // generating random data +   int array[]; +   ArrayResize(array, LIMIT); +   for(int i = 0; i < LIMIT; ++i) +   { +      array[i] = rand(); +   } +    +   ArrayPrint(array); +   // by default, the new array is not a timeseries +   PRTS(ArrayMaximum(array)); +   PRTS(ArrayMinimum(array)); +   // turn on the "serial" property +   PRTS(ArraySetAsSeries(array, true)); +   PRTS(ArrayMaximum(array)); +   PRTS(ArrayMinimum(array)); +} + +``` + +The script will log something like the following set of strings (due to random data generation, each run will be different): + +``` +22242 5909 21570 5850 18026 24740 10852 2631 24549 14635 +ArrayMaximum(array)=5 / status:0 +ArrayMinimum(array)=7 / status:0 +ArraySetAsSeries(array,true)=true / status:0 +ArrayMaximum(array)=4 / status:0 +ArrayMinimum(array)=2 / status:0 + +``` diff --git a/skills/mql5/references/book/03-common/0161-common-arrays-arrays-as-series.md b/skills/mql5/references/book/03-common/0161-common-arrays-arrays-as-series.md new file mode 100644 index 0000000..88ff729 --- /dev/null +++ b/skills/mql5/references/book/03-common/0161-common-arrays-arrays-as-series.md @@ -0,0 +1,165 @@ +# Timeseries indexing direction in arrays + +Due to the applied trading specifics, MQL5 brings additional features to working with arrays. One of them is that array elements can contain data corresponding to time points. These include for example, arrays with financial instrument quotes, price ticks, and readings of technical indicators. The chronological order of the data means that new elements are constantly added to the end of the array and their indexes increase. + +However, from the point of view of trading, it is more convenient to count from the present to the past. Then element 0 always contains the most recent, up-to-date value, element 1 always contains the previous value, and so on. + +MQL5 allows you to select and switch the direction of array indexing on the go. An array numbered from the present to the past is called a timeseries. If the indexing increase occurs from the past to the present, this is a regular array. In timeseries, the time decreases with the growth of indices. In ordinary arrays, the time increases, as in real life. + +It is important to note that an array does not have to contain time-related values in order to be able to switch the addressing order for it. It's just that this feature is most in demand and, in fact, appeared to work with historical data. + +This array attribute does not affect the layout of data in memory. Only the order of numbering changes. In particular, we could implement its analogue in MQL5 ourselves by traversing the array in a "back to front" loop. But MQL5 provides ready-made functions to hide all this routine from application programmers. + +Timeseries can be any one-dimensional dynamic array described in an MQL program, as well as external arrays passed to the MQL program from the MetaTrader 5 core, such as parameters of utility functions. For example, a special type of MQL programs, [indicators](/en/book/applications/indicators_make) receives arrays with price data of the current chart in the [OnCalculate](/en/book/applications/indicators_make/indicators_oncalculate) event handler. We will study all the features of the applied use of timeseries later, in the fifth Part of the book. + +Arrays defined in an MQL program are not timeseries by default. + +Let's consider a set of functions for determining and changing the "series" attribute of an array, as well as its "belonging" to the terminal. The general ArrayAsSeries.mq5 script with examples will be given after the description. + +bool ArrayIsSeries(const void &array[]) + +The function returns a sign of whether the specified array is a "real" timeseries, i.e., it is controlled and provided by the terminal itself. You cannot change this characteristic of an array. Such arrays are available to the MQL program in the "read-only" mode. + +In the MQL5 documentation, the terms "timeseries" and "series" are used to describe both the reverse indexing of an array and the fact that the array can "belong" to the terminal (the terminal allocates memory for it and fills it with data). In the book, we will try to avoid this ambiguity and refer to arrays with reverse indexing as "timeseries". And the terminal arrays will be just terminal's own arrays. + +You can change the indexing of any custom array of the terminal at your discretion by switching it to the timeseries mode or back to the standard one. This is done using the function ArraySetAsSeries, which is applicable not only to own, but also to custom dynamic arrays (see below). + +bool ArrayGetAsSeries(const void &array[]) + +The function returns a sign of whether the timeseries indexing mode is enabled for the specified array, that is, indexing increases in the direction from the present to the past. You can change the indexing direction using the ArraySetAsSeries function. + +The direction of indexing affects values returned by the functions ArrayBsearch, ArrayMaximum, and ArrayMinimum (see section [Comparing, sorting and searching in arrays](/en/book/common/arrays/arrays_compare_sort_search)). + +bool ArraySetAsSeries(const void &array[], bool as_series) + +The function sets the indexing direction in the array according to the as_series parameter: the true value means the reverse order of indexing, while false means the normal order of elements. + +The function returns true on successful attribute setting, or false in case of an error. + +Arrays of any type are supported, but changing the direction of indexing is prohibited for multidimensional and fixed-size arrays. + +The ArrayAsSeries.mq5 script describes several small arrays for experiments involving the above functions. + +``` +#define LIMIT 10 +  +template +void indexArray(T &array[]) +{ +   for(int i = 0; i < ArraySize(array); ++i) +   { +      array[i] = (T)(i + 1); +   } +} +  +class Dummy +{ +   int data[]; +}; +  +void OnStart() +{ +   double array2D[][2]; +   double fixed[LIMIT]; +   double dynamic[]; +   MqlRates rates[]; +   Dummy dummies[]; +    +   ArrayResize(dynamic, LIMIT); // allocating memory +   // fill in a couple of arrays with numbers: 1, 2, 3,... +   indexArray(fixed); +   indexArray(dynamic); +   ... + +``` + +We have a two-dimensional array array2D, fixed and dynamic array, all of which are of type double, as well as arrays of structures and class objects. The fixed and dynamic arrays are filled with consecutive integers (using the auxiliary function indexArray) for demonstration purposes. For other array types of arrays, we will only check the applicability of the "series" mode, since the idea of the reversal indexing effect will become clear from the example of filled arrays. + +First, make sure none of the arrays are the terminal's own array: + +``` +   PRTS(ArrayIsSeries(array2D)); // false +   PRTS(ArrayIsSeries(fixed));   // false +   PRTS(ArrayIsSeries(dynamic)); // false +   PRTS(ArrayIsSeries(rates));   // false + +``` + +All ArrayIsSeries calls return false since we defined all arrays in the MQL program. We will see the true value for parameter arrays of the function OnCalculate in indicators (in the fifth Part). + +Next, let's check the initial direction of array indexing: + +``` +   PRTS(ArrayGetAsSeries(array2D)); // false, cannot be true +   PRTS(ArrayGetAsSeries(fixed));   // false +   PRTS(ArrayGetAsSeries(dynamic)); // false +   PRTS(ArrayGetAsSeries(rates));   // false +   PRTS(ArrayGetAsSeries(dummies)); // false + +``` + +And again we will get false everywhere. + +Let's output arrays fixed and dynamic to the journal to see the original order of the elements. + +``` +   ArrayPrint(fixed, 1); +   ArrayPrint(dynamic, 1); +   /* +       1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0 10.0 +       1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0 10.0 +   */ + +``` + +Now we try to change the indexing order: + +``` +   // error: parameter conversion not allowed +   // PRTS(ArraySetAsSeries(array2D, true)); +  +   // warning: cannot be used for static allocated array +   PRTS(ArraySetAsSeries(fixed, true));   // false +  +   // after this everything is standard +   PRTS(ArraySetAsSeries(dynamic, true)); // true +   PRTS(ArraySetAsSeries(rates, true));   // true +   PRTS(ArraySetAsSeries(dummies, true)); // true + +``` + +A statement for the array2D array causes a compilation error and is therefore commented out. + +A statement for the fixed array issues a compiler warning that it cannot be applied to an array of constant size. At runtime, all 3 last statements returned success (true). Let's see how the attributes of the arrays have changed: + +``` +   // attribute checks: +   // first, whether they are native to the terminal +   PRTS(ArrayIsSeries(fixed));            // false +   PRTS(ArrayIsSeries(dynamic));          // false +   PRTS(ArrayIsSeries(rates));            // false +   PRTS(ArrayIsSeries(dummies));          // false +    +   // second, indexing direction +   PRTS(ArrayGetAsSeries(fixed));         // false +   PRTS(ArrayGetAsSeries(dynamic));       // true +   PRTS(ArrayGetAsSeries(rates));         // true +   PRTS(ArrayGetAsSeries(dummies));       // true + +``` + +As expected, the arrays didn't turn into the terminal's own arrays. However, three out of four arrays changed their indexing to timeseries mode, including an array of structures and objects. To demonstrate the result, the fixed and dynamic arrays are again displayed in the log. + +``` +   ArrayPrint(fixed, 1);    // without changes  +   ArrayPrint(dynamic, 1);  // reverse order +   /* +       1.0  2.0  3.0  4.0  5.0  6.0  7.0  8.0  9.0 10.0 +      10.0  9.0  8.0  7.0  6.0  5.0  4.0  3.0  2.0  1.0 +   */ + +``` + +Since the mode was not applied to the array of constant size, it remained unchanged. The dynamic array is now displayed in reverse order. + +If you put the array into reverse indexing mode, resize it, and then return the previous indexing, then the added elements will be inserted at the beginning of the array. diff --git a/skills/mql5/references/book/03-common/0162-common-arrays-zero-memory.md b/skills/mql5/references/book/03-common/0162-common-arrays-zero-memory.md new file mode 100644 index 0000000..c20f1f6 --- /dev/null +++ b/skills/mql5/references/book/03-common/0162-common-arrays-zero-memory.md @@ -0,0 +1,240 @@ +# Zeroing objects and arrays + +Usually, initialization or filling of variables and arrays does not cause problems. So, for simple variables, we can simply use the operator '=' in the definition statement along with [initialization](/en/book/basis/variables/initialization), or assign the desired value at any later time. + +Aggregate view initialization is available for structures (see section [Defining Structures](/en/book/oop/structs_and_unions/structs_definition)): + +``` +Struct struct = {value1, value2, ...}; + +``` + +But it is possible only if there are no dynamic arrays and strings in the structure. Moreover, the aggregate initialization syntax cannot be used to clean up a structure again. Instead, you must either assign values to each field individually or reserve an instance of the empty structure in the program and copy it to clearable instances. + +If at the same time, we are talking about an array of structures, then the source code will quickly grow due to auxiliary but necessary instructions. + +For arrays, there are the [ArrayInitialize](/en/book/common/arrays/arrays_init_fill)[ and ](/en/book/common/arrays/arrays_init_fill)[ArrayFill](/en/book/common/arrays/arrays_init_fill) functions, but they only support numeric types: an array of strings or structures cannot be filled with them. + +In such cases, the ZeroMemory function can be useful. It is not a panacea, since it has significant limitations in the scope, but it is good to know it. + +void ZeroMemory(void &entity) + +The function can be applied to a wide range of different entities: variables of simple or object types, as well as their arrays (fixed, dynamic, or multidimensional). + +Variables get the 0 value (for numbers) or its equivalent (NULL for strings and pointers). + +In the case of an array, all its elements are set to zero. Do not forget that the elements can be objects, and in turn, contain objects. In other words, the ZeroMemory function performs a deep memory cleanup in a single call. + +However, there are restrictions on valid objects. You can only populate with zeros the objects of structures and classes, which: + +- contain only public fields (i.e., they do not contain data with access type private or protected) +- do not contain fields with the const modifier +- do not contain pointers + +The first two restrictions are built into the compiler: an attempt to nullify objects with fields that do not meet the specified requirements will cause errors (see below). + +The third limitation is a recommendation: external zeroing of a pointer will make it difficult to check the integrity of the data, which is likely to lead to the loss of the associated object and to a memory leak. + +Strictly speaking, the requirement of publicity of fields in nullable objects violates the [encapsulation](/en/book/oop/classes_and_interfaces/classes_encapsulation) principle, which is inherent in class objects, and therefore ZeroMemory is mainly used with objects of simple structures and their arrays. + +Examples of working with ZeroMemory are given in the script ZeroMemory.mq5. + +The problems with the aggregate initialization list are demonstrated using the structure Simple: + +``` +#define LIMIT 5 +    +struct Simple +{ +   MqlDateTime data[]; // dynamic array disables initialization list, +   // string s; // and a string field would also forbid, +   // ClassType *ptr; // and a pointer too +   Simple() +   { +      // allocating memory, it will contain arbitrary data +      ArrayResize(data, LIMIT); +   } +}; + +``` + +In the OnStart function or in the global context, we cannot define and immediately nullify an object of such a structure: + +``` +void OnStart() +{ +   Simple simple = {}; // error: cannot be initialized with initializer list +   ... + +``` + +The compiler throws the error "cannot use initialization list". It is specific to fields like dynamic arrays, string variables, and pointers. In particular, if the data array were of a fixed size, no error would occur. + +Therefore, instead of an initialization list, we use ZeroMemory: + +``` +void OnStart() +{ +   Simple simple; +   ZeroMemory(simple); +   ... + +``` + +The initial filling with zeros could also be done in the structure constructor, but it is more convenient to do subsequent cleanups outside (or provide a method for this with the same function ZeroMemory). + +The following class is defined in Base. + +``` +class Base +{ +public: // public is required for ZeroMemory +   // const for any field will cause a compilation error when calling ZeroMemory: +   // "not allowed for objects with protected members or inheritance" +   /* const */ int x; +   Simple t;   // using a nested structure: it will also be nulled +   Base() +   { +      x = rand(); +   } +   virtual void print() const +   { +      PrintFormat("%d %d", &this, x); +      ArrayPrint(t.data); +   } +}; + +``` + +Since the class is further used in arrays of objects nullable with ZeroMemory, we are forced to write an access section public for its fields (which, in principle, is not typical for classes and is done to illustrate the requirements imposed by ZeroMemory). Also, note that fields cannot have the modifier const. Otherwise, we'll get a compilation error with text that unfortunately doesn't really fit the problem: "forbidden for objects with protected members or inheritance". + +The class constructor fills the field x with a random number so that later you can clearly see its cleaning by the function ZeroMemory. The print method displays the contents of all fields for analysis, including the unique object number (descriptor) &this. + +MQL5 does not prevent ZeroMemory from being applied to a pointer variable: + +``` +   Base *base = new Base(); +   ZeroMemory(base); // will set the pointer to NULL but leave the object + +``` + +However, this should not be done, because the function resets only the base variable itself, and, if it referred to an object, this object will remain "hanging" in memory, inaccessible from the program due to the loss of the pointer. + +You can nullify a pointer only after the pointer instance has been freed using the delete operator. Furthermore, it is easier to reset a separate pointer from the above example, like any other simple variable (non-composite), using an assignment operator. It makes sense to use ZeroMemory for composite objects and arrays. + +The function allows you to work with objects of the class hierarchy. For example, we can describe the derivative of the Dummy class derived from Base: + +``` +class Dummy : public Base +{ +public: +   double data[]; // could also be multidimensional: ZeroMemory will work +   string s; +   Base *pointer; // public pointer (dangerous) +    +public: +   Dummy() +   { +      ArrayResize(data, LIMIT); +       +      // due to subsequent application of ZeroMemory to the object +      // we'll lose the 'pointer' +      // and get warnings when the script ends +      // about undeleted objects of type Base +      pointer = new Base(); +   } +    +   ~Dummy() +   { +      // due to the use of ZeroMemory, this pointer will be lost +      // and will not be freed +      if(CheckPointer(pointer) != POINTER_INVALID) delete pointer; +   } +    +   virtual void print() const override +   { +      Base::print(); +      ArrayPrint(data); +      Print(pointer); +      if(CheckPointer(pointer) != POINTER_INVALID) pointer.print(); +   } +}; + +``` + +It includes fields with a dynamic array of type double, string and pointer of type Base (this is the same type from which the class is derived, but it is used here only to demonstrate the pointer problems, so as not to describe another dummy class). When the ZeroMemory function nullifies the Dummy object, an object at pointer is lost and cannot be freed in the destructor. As a result, this leads to warnings about memory leaks in the remaining objects after the script terminates. + +ZeroMemory is used in OnStart to clear the Dummy objects array: + +``` +void OnStart() +{ +   ... +   Print("Initial state"); +   Dummy array[]; +   ArrayResize(array, LIMIT); +   for(int i = 0; i < LIMIT; ++i) +   { +      array[i].print(); +   } +   ZeroMemory(array); +   Print("ZeroMemory done"); +   for(int i = 0; i < LIMIT; ++i) +   { +      array[i].print(); +   } + +``` + +The log will output something like the following (the initial state will be different because it prints the contents of the "dirty", newly allocated memory; here is a small code part): + +``` +Initial state +1048576 31539 +     [year]     [mon]    [day] [hour] [min] [sec] [day_of_week] [day_of_year] +[0]       0     65665       32      0     0     0             0             0 +[1]       0         0        0      0     0     0         65624             8 +[2]       0         0        0      0     0     0             0             0 +[3]       0         0        0      0     0     0             0             0 +[4] 5242880 531430129 51557552      0     0 65665            32             0 +0.0 0.0 0.0 0.0 0.0 +... +ZeroMemory done +1048576 0 +    [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] +[0]      0     0     0      0     0     0             0             0 +[1]      0     0     0      0     0     0             0             0 +[2]      0     0     0      0     0     0             0             0 +[3]      0     0     0      0     0     0             0             0 +[4]      0     0     0      0     0     0             0             0 +0.0 0.0 0.0 0.0 0.0 +... +5 undeleted objects left +5 objects of type Base left +3200 bytes of leaked memory + +``` + +To compare the state of objects before and after cleaning, use descriptors. + +So, a single call to ZeroMemory is able to reset the state of an arbitrary branched data structure (arrays, structures, arrays of structures with nested structure fields and arrays). + +Finally, let's see how ZeroMemory can solve the problem of string array initialization. The ArrayInitialize and ArrayFill functions do not work with strings. + +``` +   string text[LIMIT] = {}; +   // an algorithm populates and uses 'text' +   // ... +   // then you need to re-use the array +   // calling functions gives errors: +   // ArrayInitialize(text, NULL); +   //      `-> no one of the overloads can be applied to the function call +   // ArrayFill(text, 0, 10, NULL); +   //      `->  'string' type cannot be used in ArrayFill function +   ZeroMemory(text);               // ok + +``` + +In the commented instructions, the compiler would generate errors, stating that the type string is not supported in these functions. + +The way out of this problem is the ZeroMemory function. diff --git a/skills/mql5/references/book/03-common/0163-common-maths.md b/skills/mql5/references/book/03-common/0163-common-maths.md new file mode 100644 index 0000000..ec0f3d4 --- /dev/null +++ b/skills/mql5/references/book/03-common/0163-common-maths.md @@ -0,0 +1,15 @@ +# Mathematical functions + +The most popular mathematical functions are usually available in all modern programming languages, and MQL5 is no exception. In this chapter, we'll take a look at several groups of out-of-the-box functions. These include rounding, trigonometric, hyperbolic, exponential, logarithmic, and power functions, as well as a few special ones, such as generating random numbers and checking real numbers for normality. + +Most of the functions have two names: full (with the prefix "Math" and capitalization) and abbreviated (without a prefix, in lowercase letters). We will provide both options: they work the same way. The choice can be made based on the formatting style of the source codes. + +Since mathematical functions perform some calculations and return a result as a real number, potential errors can lead to a situation where the result is undefined. For example, you cannot take the square root of a negative number or take the logarithm of zero. In such cases, the functions return special values that are not numbers (NaN, Not A Number). We have already faced them in the sections [Real numbers](/en/book/basis/builtin_types/float_numbers), [Arithmetic operations](/en/book/basis/expressions/operators_arithmetic), and [Numbers to strings and back](/en/book/common/conversions/conversions_numbers). The number correctness and the absence of errors can be analyzed using the MathIsValidNumber and MathClassify functions (see section [Checking real numbers for normality](/en/book/common/maths/maths_nan)). + +The presence of at least one operand with a value of NaN will cause any subsequent computations implying this operand, including function calls, to also result in NaN. + +For self-study and visual material, you can use the MathPlot.mq5 script as an attachment, which allows you to display mathematical function graphs with one argument from those described. The script uses the standard drawing library Graphic.mqh provided in MetaTrader 5 (outside the scope of this book). Below is a sample of what a hyperbolic sine curve might look like in the MetaTrader 5 window. + +![Hyperbolic sine chart in the MetaTrader 5 window](pics/sinhplot.png) + +Hyperbolic sine chart in the MetaTrader 5 window diff --git a/skills/mql5/references/book/03-common/0164-common-maths-maths-abs.md b/skills/mql5/references/book/03-common/0164-common-maths-maths-abs.md new file mode 100644 index 0000000..f37ca08 --- /dev/null +++ b/skills/mql5/references/book/03-common/0164-common-maths-maths-abs.md @@ -0,0 +1,75 @@ +# The absolute value of a number + +The MQL5 API provides the MathAbs function which can remove the minus sign from the number if it exists. Therefore, there is no need to manually code longer equivalents like this: + +``` +if(x < 0) x = -x; + +``` + +numeric MathAbs(numeric value) ≡ numeric fabs(numeric value) + +The function returns the absolute value of the number passed to it, i.e., its modulus. The argument can be a number of any type. In other words, the function is overloaded for char/uchar, short/ushort, int/uint, long/ulong, float and double, although for unsigned types the values are always non-negative. + +When passing a string, it will be implicitly converted to a double number, and the compiler will generate a relevant warning. + +The type of the return value is always the same as the type of the argument, and therefore the compiler may need to cast the value to the receiving variable type if the types are different. + +Function usage examples are available in the MathAbs.mq5 file. + +``` +void OnStart() +{ +   double x = 123.45; +   double y = -123.45; +   int i = -1; +    +   PRT(MathAbs(x)); // 123.45, number left "as is" +   PRT(MathAbs(y)); // 123.45, minus sign gone  +   PRT(MathAbs(i)); // 1, int is handled naturally +    +   int k = MathAbs(i);  // no warning: type int for parameter and result +    +   // situations with warnings: +   // double to long conversion required +   long j = MathAbs(x); // possible loss of data due to type conversion +    +   // need to be converted from large type (4 bytes) to small type (2 bytes) +   short c = MathAbs(i); // possible loss of data due to type conversion +   ... + +``` + +It's important to note that converting a signed integer to an unsigned integer is not equivalent to taking the modulus of a number: + +``` +   uint u_cast = i; +   uint u_abs = MathAbs(i); +   PRT(u_cast);             // 4294967295, 0xFFFFFFFF +   PRT(u_abs);              // 1 + +``` + +Also note that the number 0 can have a sign: + +``` +   ... +   double n = 0; +   double z = i * n; +   PRT(z);               // -0.0 +   PRT(MathAbs(z));      //  0.0 +   PRT(z == MathAbs(z)); // true +} + +``` + +One of the best examples of how to use MathAbs is to test two real numbers for equality. As is known, real numbers have a limited accuracy of representing values, which can further degrade in the course of lengthy calculations (for example, the sum of ten values 0.1 does not give exactly 1.0). Strict condition value1 == value2 can give false in most cases, when purely speculative equality should hold. + +Therefore, to compare real values, the following notation is usually used: + +``` +MathAbs(value1 - value2) < EPS + +``` + +where EPS is a small positive value which indicates a precision (see an example in the [Comparison operations](/en/book/basis/expressions/operators_relational) section). diff --git a/skills/mql5/references/book/03-common/0165-common-maths-maths-max-min.md b/skills/mql5/references/book/03-common/0165-common-maths-maths-max-min.md new file mode 100644 index 0000000..82061a0 --- /dev/null +++ b/skills/mql5/references/book/03-common/0165-common-maths-maths-max-min.md @@ -0,0 +1,36 @@ +# Maximum and minimum of two numbers + +To find the largest or smallest number out of two, MQL5 offers functions MathMax and MathMin. Their short aliases are respectively fmax and fmin. + +numeric MathMax(numeric value1, numeric value2) ≡ numeric fmax(numeric value1, numeric value2) + +numeric MathMin(numeric value1, numeric value2) ≡ numeric fmin(numeric value1, numeric value2) + +The functions return the maximum or minimum of the two values passed. The functions are overloaded for all built-in types. + +If parameters of different types are passed to the function, then the parameter of the "lower" type is automatically converted to the "higher" type, for example, in a pair of types int and double, int will be brought to double. For more information on implicit type casting, see section [Arithmetic type conversions](/en/book/basis/conversion/conversion_arithmetic). The return type corresponds to the "highest" type. + +When there is a parameter of type string, it will be "senior", that is, everything is reduced to a string. Strings will be compared lexicographically, as in the [StringCompare](/en/book/common/strings/strings_comparison) function. + +The MathMaxMin.mq5 script demonstrates the functions in action. + +``` +void OnStart() +{ +   int i = 10, j = 11; +   double x = 5.5, y = -5.5; +   string s = "abc"; +    +   // numbers    +   PRT(MathMax(i, j)); // 11 +   PRT(MathMax(i, x)); // 10 +   PRT(MathMax(x, y)); // 5.5 +   PRT(MathMax(i, s)); // abc +    +   // type conversions +   PRT(typename(MathMax(i, j))); // int, as is +   PRT(typename(MathMax(i, x))); // double +   PRT(typename(MathMax(i, s))); // string +} + +``` diff --git a/skills/mql5/references/book/03-common/0166-common-maths-maths-rounding.md b/skills/mql5/references/book/03-common/0166-common-maths-maths-rounding.md new file mode 100644 index 0000000..40ebcf3 --- /dev/null +++ b/skills/mql5/references/book/03-common/0166-common-maths-maths-rounding.md @@ -0,0 +1,41 @@ +# Rounding functions + +The MQL5 API includes several functions for rounding numbers to the nearest integer (in one direction or another). Despite the rounding operation, all functions return a number of type double (with an empty fractional part). + +From a technical point of view, they accept arguments of any numeric type, but only real numbers are rounded, and integers are only converted to double. + +If you want to round up to a specific sign, use NormalizeDouble (see section [Normalization of doubles](/en/book/common/conversions/conversions_normalize)). + +Examples of working with functions are given in the file MathRound.mq5. + +double MathRound(numeric value) ≡ double round(numeric value) + +The function rounds a number up or down to the nearest integer. + +``` +   PRT((MathRound(5.5)));  // 6.0 +   PRT((MathRound(-5.5))); // -6.0 +   PRT((MathRound(11)));   // 11.0 +   PRT((MathRound(-11)));  // -11.0 + +``` + +If the value of the fractional part is greater than or equal to 0.5, the mantissa is increased by one (regardless of the sign of the number). + +double MathCeil(numeric value) ≡ double ceil(numeric value) + +double MathFloor(numeric value) ≡ double floor(numeric value) + +The functions return the closest greater integer value (for ceil) or closest lower integer value (for floor) to the transferred value. If value is already equal to an integer (has a zero fractional part), this integer is returned. + +``` +   PRT((MathCeil(5.5)));   // 6.0 +   PRT((MathCeil(-5.5)));  // -5.0 +   PRT((MathFloor(5.5)));  // 5.0 +   PRT((MathFloor(-5.5))); // -6.0 +   PRT((MathCeil(11)));    // 11.0 +   PRT((MathCeil(-11)));   // -11.0 +   PRT((MathFloor(11)));   // 11.0 +   PRT((MathFloor(-11)));  // -11.0 + +``` diff --git a/skills/mql5/references/book/03-common/0167-common-maths-maths-mod.md b/skills/mql5/references/book/03-common/0167-common-maths-maths-mod.md new file mode 100644 index 0000000..de7a9ee --- /dev/null +++ b/skills/mql5/references/book/03-common/0167-common-maths-maths-mod.md @@ -0,0 +1,21 @@ +# Remainder after division (Modulo operation) + +To divide integers with remainder, MQL5 has the built-in modulo operator '%', described in the section [Arithmetic operations](/en/book/basis/expressions/operators_arithmetic). However, this operator is not applicable to real numbers. In the case when the divisor, the dividend, or both operands are real, you should use the function MathMod (or short form fmod). + +double MathMod(double dividend, double divider) ≡ double fmod(double dividend, double divider) + +The function returns the real remainder after dividing the first passed number (dividend) by the second (divider). + +If any argument is negative, the sign of the result is determined by the rules described in the above [section](/en/book/basis/expressions/operators_arithmetic). + +Examples of how the function works are available in the script MathMod.mq5. + +``` +   PRT(MathMod(10.0, 3));     // 1.0 +   PRT(MathMod(10.0, 3.5));   // 3.0 +   PRT(MathMod(10.0, 3.49));  // 3.02 +   PRT(MathMod(10.0, M_PI));  // 0.5752220392306207 +   PRT(MathMod(10.0, -1.5));  // 1.0, the sign is gone +   PRT(MathMod(-10.0, -1.5)); // -1.0 + +``` diff --git a/skills/mql5/references/book/03-common/0168-common-maths-maths-pow-sqrt.md b/skills/mql5/references/book/03-common/0168-common-maths-maths-pow-sqrt.md new file mode 100644 index 0000000..1713a79 --- /dev/null +++ b/skills/mql5/references/book/03-common/0168-common-maths-maths-pow-sqrt.md @@ -0,0 +1,38 @@ +# Powers and roots + +The MQL5 API provides a generic function MathPow for raising a number to an arbitrary power, as well as a function for a special case with a power of 0.5, more familiar to us as the operation of extracting a square root MathSqrt. + +To test the functions, use the MathPowSqrt.mq5 script. + +double MathPow(double base, double exponent) ≡ double pow(double base, double exponent) + +The function raises the base to the specified power exponent. + +``` +   PRT(MathPow(2.0, 1.5));  // 2.82842712474619 +   PRT(MathPow(2.0, -1.5)); // 0.3535533905932738 +   PRT(MathPow(2.0, 0.5));  // 1.414213562373095 + +``` + +double MathSqrt(double value) ≡ double sqrt(double value) + +The function returns the square root of a number. + +``` +   PRT(MathSqrt(2.0));      // 1.414213562373095 +   PRT(MathSqrt(-2.0));     // -nan(ind) + +``` + +MQL5 defines several constants containing ready-made calculation values involving sqrt. + +| Constant | Description | Value | +| --- | --- | --- | +| M_SQRT2 | sqrt(2.0) | 1.41421356237309504880 | +| M_SQRT1_2 | 1 / sqrt(2.0) | 0.707106781186547524401 | +| M_2_SQRTPI | 2.0 / sqrt(M_PI) | 1.12837916709551257390 | + +Here M_PI is the Pi number (π=3.14159265358979323846, see further along the section [Trigonometric functions](/en/book/common/maths/maths_trig)). + +All built-in constants are described in the [documentation](https://www.mql5.com/en/docs/constants/namedconstants/mathsconstants). diff --git a/skills/mql5/references/book/03-common/0169-common-maths-maths-exp-log.md b/skills/mql5/references/book/03-common/0169-common-maths-maths-exp-log.md new file mode 100644 index 0000000..003ddd7 --- /dev/null +++ b/skills/mql5/references/book/03-common/0169-common-maths-maths-exp-log.md @@ -0,0 +1,88 @@ +# Exponential and logarithmic functions + +Calculation of exponential and logarithmic functions is available in MQL5 using the corresponding API section. + +The absence of the binary logarithm in the API, which is often required in computer science and combinatorics, is not a problem, since it is easy to calculate, upon request, through the available natural or decimal logarithm functions. + +``` +log2(x) = log(x) / log(2) = log(x) / M_LN2 +log2(x) = log10(x) / log10(2) + +``` + +Here log and log10 are available logarithmic functions (based on e and 10, respectively), M_LN2 is a built-in constant equal to log(2). + +The following table lists all the constants that can be useful in logarithmic calculations. + +| Constant | Description | Value | +| --- | --- | --- | +| M_E | e | 2.71828182845904523536 | +| M_LOG2E | log2(e) | 1.44269504088896340736 | +| M_LOG10E | log10(e) | 0.434294481903251827651 | +| M_LN2 | ln(2) | 0.693147180559945309417 | +| M_LN10 | ln(10) | 2.30258509299404568402 | + +Examples of the functions described below are collected in the file MathExp.mq5. + +double MathExp(double value) ≡ double exp(double value) + +The function returns the exponent, i.e., the number e (available as a predefined constant M_E) raised to the specified power value. On overflow, the function returns inf (a kind of NaN for infinity). + +``` +   PRT(MathExp(0.5));      // 1.648721270700128 +   PRT(MathPow(M_E, 0.5)); // 1.648721270700128 +   PRT(MathExp(10000.0));  // inf, NaN + +``` + +double MathLog(double value) ≡ double log(double value) + +The function returns the natural logarithm of the passed number. If value is negative, the function returns -nan(ind) (NaN "undefined value"). If value is 0, the function returns inf (NaN "infinity"). + +``` +   PRT(MathLog(M_E));     // 1.0 +   PRT(MathLog(10000.0)); // 9.210340371976184 +   PRT(MathLog(0.5));     // -0.6931471805599453 +   PRT(MathLog(0.0));     // -inf, NaN +   PRT(MathLog(-0.5));    // -nan(ind) +   PRT(Log2(128));        // 7 + +``` + +The last line uses the implementation of the binary logarithm through MathLog: + +``` +double Log2(double value) +{ +   return MathLog(value) / M_LN2; +} + +``` + +double MathLog10(double value) ≡ double log10(double value) + +The function returns the decimal logarithm of a number. + +``` +   PRT(MathLog10(10.0)); // 1.0 +   PRT(MathLog10(10000.0)); // 4.0 + +``` + +double MathExpm1(double value) ≡ double expm1(double value) + +The function returns the value of the expression (MathExp(value) - 1). In economic calculations, the function is used to calculate the effective interest (revenue or payment) per unit of time in a compound interest scheme when the number of periods tends to infinity. + +``` +   PRT(MathExpm1(0.1)); // 0.1051709180756476 + +``` + +double MathLog1p(double value) ≡ double log1p(double value) + +The function returns the value of the expression MathLog(1 + value), i.e., it performs the opposite action to the function MathExpm1. + +``` +   PRT(MathLog1p(0.1)); // 0.09531017980432487 + +``` diff --git a/skills/mql5/references/book/03-common/0170-common-maths-maths-trig.md b/skills/mql5/references/book/03-common/0170-common-maths-maths-trig.md new file mode 100644 index 0000000..941ff8f --- /dev/null +++ b/skills/mql5/references/book/03-common/0170-common-maths-maths-trig.md @@ -0,0 +1,88 @@ +# Trigonometric functions + +MQL5 provides the three main trigonometric functions (MathCos, MathSin, MathTan) and their inverses (MathArccos, MathArcsin, MathArctan). They all work with angles in radians. For angles in degrees, use the formula: + +``` +radians = degrees * M_PI / 180 + +``` + +Here M_PI is one of several constants with trigonometric quantities (pi and its derivatives) built into the language. + +| Constant | Description | Value | +| --- | --- | --- | +| M_PI | π | 3.14159265358979323846 | +| M_PI_2 | π/2 | 1.57079632679489661923 | +| M_PI_4 | π/4 | 0.785398163397448309616 | +| M_1_PI | 1/π | 0.318309886183790671538 | +| M_2_PI | 2/π | 0.636619772367581343076 | + +The arc tangent can also be calculated for a quantity represented by the ratio of two coordinates y and x: this extended version is called MathArctan2; it is able to restore angles in the full range of the circle from -M_PI to +M_PI, unlike MathArctan, which is limited to -M_PI_2 to +M_PI_2. + +![Trigonometric functions and quadrants of the unit circle](pics/trigcrcl.png) + +Trigonometric functions and quadrants of the unit circle + +Examples of calculations are given in the script MathTrig.mq5 (see after the descriptions). + +double MathCos(double value) ≡ double cos(double value) + +double MathSin(double value) ≡ double sin(double value) + +The functions return, respectively, the cosine and sine of the passed number (the angle is in radians). + +double MathTan(double value) ≡ double tan(double value) + +The function returns the tangent of the passed number (the angle is in radians). + +double MathArccos(double value) ≡ double acos(double value) + +double MathArcsin(double value) ≡ double asin(double value) + +The functions return the value, respectively, of the arc cosine and arc sine of the passed number, i.e., the angle in radians. If x = MathCos(t), then t = MathArccos(x). The sine and arcsine have a similar scheme. If y = MathSin(t), then t = MathArcsin(y). + +The parameter must be between -1 and +1. Otherwise, the function will return NaN. + +The result of the arccosine is in the range from 0 to M_PI, and the result of the arcsine is from -M_PI_2 to +M_PI_2. The indicated ranges are called the main ranges, since the functions are multi-valued, i.e., their values are periodically repeated. The selected half-periods completely cover the definition area from -1 to +1. + +The resulting angle for the cosine lies in the upper semicircle, and the symmetric solution in the lower semicircle can be obtained by adding a sign, i.e.t=-t. For the sine, the resulting angle is in the right semicircle, and the second solution in the left semicircle is M_PI-t (if for negative t it is also required to obtain a negative additional angle, then -M_PI-t). + +double MathArctan(double value) ≡ double atan(double value) + +The function returns the value of the arc tangent for the passed number, i.e., the angle in radians, in the range from -M_PI_2 to +M_PI_2. + +The function is inverse to MathTan, but with one caveat. + +Please note that the period of the tangent is 2 times less than the full period (circumference) due to the fact that the ratio of sine and cosine is repeated in opposite quadrants (quarters of a circle) due to superposition of signs. As a result, the tangent value alone is not sufficient to uniquely determine the original angle over the full range from -M_PI to +M_PI. This can be done using the function MathArctan2, in which the tangent is represented by two separate components. + +double MathArctan2(double y, double x) ≡ double atan2(double y, double x) + +The function returns in radians the value of the angle, the tangent of which is equal to the ratio of two specified numbers: coordinates along the y axis and along the x axis. + +The result (let's denote it as r) lies in the range from -M_PI to +M_PI, and the condition MathTan(r) = y / x is met for it. + +The function takes into account the sign of both arguments to determine the correct quadrant (subject to boundary conditions, when either x, or y are equal to 0, that is, they are on the border of the quadrants). + +- 1 – x >= 0, y >= 0, 0 <= r <= M_PI_2 +- 2 – x < 0, y >= 0, M_PI_2 < r <= M_PI +- 3 – x < 0, y < 0, -M_PI < r < -M_PI_2 +- 4 – x >= 0, y < 0, -M_PI_2 <= r < 0 + +Below are the results of calling trigonometric functions in the script MathTrig.mq5. + +``` +void OnStart() +{ +   PRT(MathCos(1.0));     // 0.5403023058681397 +   PRT(MathSin(1.0));     // 0.8414709848078965 +   PRT(MathTan(1.0));     // 1.557407724654902 +   PRT(MathTan(45 * M_PI / 180.0)); // 0.9999999999999999 +    +   PRT(MathArccos(1.0));         // 0.0 +   PRT(MathArcsin(1.0));         // 1.570796326794897 == M_PI_2 +   PRT(MathArctan(0.5));         // 0.4636476090008061, Q1 +   PRT(MathArctan2(1.0, 2.0));   // 0.4636476090008061, Q1 +   PRT(MathArctan2(-1.0, -2.0)); // -2.677945044588987, Q3 +} + +``` diff --git a/skills/mql5/references/book/03-common/0171-common-maths-maths-hyper.md b/skills/mql5/references/book/03-common/0171-common-maths-maths-hyper.md new file mode 100644 index 0000000..f5ab64f --- /dev/null +++ b/skills/mql5/references/book/03-common/0171-common-maths-maths-hyper.md @@ -0,0 +1,47 @@ +# Hyperbolic functions + +The MQL5 API includes a set of direct and inverse hyperbolic functions. + +![Hyperbolic functions](pics/hyper.png) + +Hyperbolic functions + +double MathCosh(double value) ≡ double cosh(double value) + +double MathSinh(double value) ≡ double sinh(double value) + +double MathTanh(double value) ≡ double tanh(double value) + +The three basic functions calculate the hyperbolic cosine, sine and tangent. + +double MathArccosh(double value) ≡ double acosh(double value) + +double MathArcsinh(double value) ≡ double asinh(double value) + +double MathArctanh(double value) ≡ double atanh(double value) + +The three inverse functions calculate the hyperbolic inverse cosine, inverse sine, and arc tangent. + +For the arc cosine, the argument must be greater than or equal to +1. Otherwise, the function will return NaN. + +The arc tangent is defined from -1 to +1. If the argument is beyond these limits, the function will return NaN. + +Examples of hyperbolic functions are shown in the MathHyper.mq5 script. + +``` +void OnStart() +{ +   PRT(MathCosh(1.0));    // 1.543080634815244 +   PRT(MathSinh(1.0));    // 1.175201193643801 +   PRT(MathTanh(1.0));    // 0.7615941559557649 +    +   PRT(MathArccosh(0.5)); // nan +   PRT(MathArcsinh(0.5)); // 0.4812118250596035 +   PRT(MathArctanh(0.5)); // 0.5493061443340549 +    +   PRT(MathArccosh(1.5)); // 0.9624236501192069 +   PRT(MathArcsinh(1.5)); // 1.194763217287109 +   PRT(MathArctanh(1.5)); // nan +} + +``` diff --git a/skills/mql5/references/book/03-common/0172-common-maths-maths-nan.md b/skills/mql5/references/book/03-common/0172-common-maths-maths-nan.md new file mode 100644 index 0000000..e7cac51 --- /dev/null +++ b/skills/mql5/references/book/03-common/0172-common-maths-maths-nan.md @@ -0,0 +1,123 @@ +# Normality test for real numbers + +Since calculations with real numbers can have abnormal situations, such as going beyond the scope of a function, obtaining mathematical infinity, lost order, and others, the result may not contain a number. Instead, it may contain a special value that actually describes the nature of the problem. All such special values have a generic name "not a number" (Not A Number, NaN). + +We have already faced them in the previous sections of the book. In particular, when outputting to a journal (see section [Numbers to strings and vice versa](/en/book/common/conversions/conversions_numbers)) they are displayed as text labels (for example, nan(ind), +inf and others). Another feature is that a single NaN value among the operands of any expression is enough for the entire expression to stop evaluating correctly and begin to give the result NaN. The only exceptions are "non-numbers" representing the plus/minus of infinity: if you divide something by them, you get zero. However, there is an expected exception here: if we divide infinity by infinity, we again get NaN. + +Therefore, it is important for programs to determine the moment when NaN appears in the calculations and handle the situation in a special way: signal an error, substitute some acceptable default value, or repeat the calculation with other parameters (for example, reduce the accuracy/step of the iterative algorithm). + +There are 2 functions in MQL5 that allow you to analyze a real number for normality:MathIsValidNumber gives a simple answer: yes (true) or not (false), and MathClassify produces more detailed categorization. + +At the physical level, all special values are encoded in a number with a special combination of bits that is not used to represent ordinary numbers. For types double and float these encodings are, of course, different. Let's take a look at double behind the scenes (as it is more in demand than float). + +In the chapter [Nested templates](/en/book/oop/templates/templates_nested), we created a Converter class for switching views by combining two different types in a union. Let's use this class to study the NaN bit device. + +For convenience, we will move the class to a separate header file ConverterT.mqh. Let's connect this mqh-file in the test script MathInvalid.mq5 and create an instance of a converter for a bunch of types double/ulong (the order is not important as the converter is able to work in both directions). + +``` +static Converter NaNs; + +``` + +The combination of bits in NaN is standardized, so let's take a few commonly used values represented by constants ulong, and see how the built-in functions react to them. + +``` +// basic NaNs +#define NAN_INF_PLUS  0x7FF0000000000000 +#define NAN_INF_MINUS 0xFFF0000000000000 +#define NAN_QUIET     0x7FF8000000000000 +#define NAN_IND_MINUS 0xFFF8000000000000 +    +// custom NaN examples +#define NAN_QUIET_1   0x7FF8000000000001 +#define NAN_QUIET_2   0x7FF8000000000002 +    +static double pinf = NaNs[NAN_INF_PLUS];  // +infinity +static double ninf = NaNs[NAN_INF_MINUS]; // -infinity +static double qnan = NaNs[NAN_QUIET];     // quiet NaN +static double nind = NaNs[NAN_IND_MINUS]; // -nan(ind) +    +void OnStart() +{ +   PRT(MathIsValidNumber(pinf));               // false +   PRT(EnumToString(MathClassify(pinf)));      // FP_INFINITE +   PRT(MathIsValidNumber(nind));               // false +   PRT(EnumToString(MathClassify(nind)));      // FP_NAN +   ... +} + +``` + +As expected, the results were the same. + +Let's view the formal description of the MathIsValidNumber and MathClassify functions and then continue with the tests. + +bool MathIsValidNumber(double value) + +The function checks the correctness of a real number. The parameter can be of type double or float. The resulting true means the correct number, and false means "not a number" (one of the varieties of NaN). + +ENUM_FP_CLASS MathClassify(double value) + +The function returns the category of a real number (of type double or float) which is one of the enum ENUM_FP_CLASS values: + +- FP_NORMAL is a normal number. +- FP_SUBNORMAL is a number less than the minimum number representable in a normalized form (for example, for the type double these are values less than DBL_MIN, 2.2250738585072014e-308); loss of order (accuracy). +- FP_ZERO is zero (positive or negative). +- FP_INFINITE is infinity (positive or negative). +- FP_NAN means all other types of "non-numbers" (subdivided into families of "silent" and "signal" NaN). + +MQL5 does not provide alerting NaNs which are used in the exceptions mechanism and allows the interception and response to critical errors within the program. There is no such mechanism in MQL5, so, for example, in case of a zero division, the MQL program simply terminates its work (unloads from the chart). + +There can be many "quiet" NaNs, and you can construct them using a converter to differentiate and handle non-standard states in your computational algorithms. + +Let's perform some calculations in MathInvalid.mq5 to visualize how the numbers of different categories can be obtained. + +``` + // calculations with double +   PRT(MathIsValidNumber(0));                      // true +   PRT(EnumToString(MathClassify(0)));             // FP_ZERO +   PRT(MathIsValidNumber(M_PI));                   // true +   PRT(EnumToString(MathClassify(M_PI)));          // FP_NORMAL +   PRT(DBL_MIN / 10);                              // 2.225073858507203e-309 +   PRT(MathIsValidNumber(DBL_MIN / 10));           // true +   PRT(EnumToString(MathClassify(DBL_MIN / 10)));  // FP_SUBNORMAL +   PRT(MathSqrt(-1.0));                            // -nan(ind) +   PRT(MathIsValidNumber(MathSqrt(-1.0)));         // false +   PRT(EnumToString(MathClassify(MathSqrt(-1.0))));// FP_NAN +   PRT(MathLog(0));                                // -inf +   PRT(MathIsValidNumber(MathLog(0)));             // false +   PRT(EnumToString(MathClassify(MathLog(0))));    // FP_INFINITE +    + // calculations with float +   PRT(1.0f / FLT_MIN / FLT_MIN);                             // inf +   PRT(MathIsValidNumber(1.0f / FLT_MIN / FLT_MIN));          // false +   PRT(EnumToString(MathClassify(1.0f / FLT_MIN / FLT_MIN))); // FP_INFINITE + +``` + +We can use the converter in the opposite direction: to get its bit representation by value double, and thereby detect "non-numbers": + +``` +   PrintFormat("%I64X", NaNs[MathSqrt(-1.0)]);      // FFF8000000000000 +   PRT(NaNs[MathSqrt(-1.0)] == NAN_IND_MINUS);      // true, nind + +``` + +The PrintFormat function is similar to [StringFormat](/en/book/common/strings/strings_format); the only difference is that the result is immediately printed to the log, and not to a string. + +Finally, let's make sure that "not numbers" are always not equal: + +``` +   // NaN != NaN always true +   PRT(MathSqrt(-1.0) != MathSqrt(-1.0)); // true +   PRT(MathSqrt(-1.0) == MathSqrt(-1.0)); // false + +``` + +To get NaN or infinity in MQL5, there is a method based on casting the strings "nan" and "inf" to double. + +``` +double nan = (double)"nan"; +double infinity = (double)"inf"; + +``` diff --git a/skills/mql5/references/book/03-common/0173-common-maths-maths-rand.md b/skills/mql5/references/book/03-common/0173-common-maths-maths-rand.md new file mode 100644 index 0000000..6daf0cd --- /dev/null +++ b/skills/mql5/references/book/03-common/0173-common-maths-maths-rand.md @@ -0,0 +1,70 @@ +# Random number generation + +Many algorithms in trading require the generation of random numbers. MQL5 provides two functions that initialize and then poll the pseudo-random integer generator. + +To get a better "randomness", you can use the Alglib library available in MetaTrader 5 (see MQL5/Include/Math/Alglib/alglib.mqh). + +void MathSrand(int seed) ≡ void srand(int seed) + +The function sets some initial state of the pseudo-random integer generator. It should be called once before starting the algorithm. The random values themselves should be obtained using the sequential call of the MathRand function. + +By initializing a generator with the same seed value, you can get reproducible sequences of numbers. The seed value is not the first random number obtained from MathRand. The generator maintains some internal state, which at each moment of time (between calls to it for a new random number) is characterized by an integer value which is available from the program as the built-in uint variable [_RandomSeed](/en/book/common/environment/env_variables). It is this initial state value that establishes the MathSrand call. + +Generator operation on every call to MathRand is described by two formulas: + +``` +Xn = Tf(Xp) +R = Gf(Xn) + +``` + +The Tf function is called transition. It calculates the new internal state of the Xn generator based on the previous Xp state. + +The Gf function generates another "random" value that the function MathRand will return, using a new internal state for this. + +In MQL5, these formulas are implemented as follows (pseudocode): + +``` +Tf: _RandomSeed = _RandomSeed * 214013 + 2531011 +Gf: MathRand = (_RandomSeed >> 16) & 0x7FFF + +``` + +It is recommended to pass the [GetTickCount](/en/book/common/timing/timing_count) or [TimeLocal](/en/book/common/timing/timing_local_server) function as the seed value. + +int MathRand() ≡ int rand() + +The function returns a pseudo-random integer in the range from 0 to 32767. The sequence of generated numbers varies depending on the opening initialization done by calling MathSrand. + +An example of working with the generator is given in the MathRand.mq5 file. It calculates statistics on the distribution of generated numbers over a given number of subranges (baskets). Ideally, we should get a uniform distribution. + +``` +#define LIMIT 1000 // number of attempts (generated numbers) +#define STATS 10   // number of baskets +    +int stats[STATS] = {}; // calculation of statistics of hits in baskets +    +void OnStart() +{ +   const int bucket = 32767 / STATS; +   // generator reset +   MathSrand((int)TimeLocal()); +   // repeat the experiment in a loop +   for(int i = 0; i < LIMIT; ++i) +   { +      // getting a new random number and updating statistics +      stats[MathRand() / bucket]++; +   } +   ArrayPrint(stats); +} + +``` + +An example of results for three runs (each time we will get a new sequence): + +``` + 96  93 117  76  98  88 104 124 113  91 +110  81 106  88 103  90 105 102 106 109 + 89  98  98 107 114  90 101 106  93 104 + +``` diff --git a/skills/mql5/references/book/03-common/0174-common-maths-maths-byte-swap.md b/skills/mql5/references/book/03-common/0174-common-maths-maths-byte-swap.md new file mode 100644 index 0000000..64f7e57 --- /dev/null +++ b/skills/mql5/references/book/03-common/0174-common-maths-maths-byte-swap.md @@ -0,0 +1,71 @@ +# Endianness control in integers + +Various information systems, at the hardware level, use different byte orders when representing numbers in memory. Therefore, when integrating MQL programs with the "outside world", in particular, when implementing network communication protocols or reading/writing files of common formats, it may be necessary to change the byte order. + +Windows computers apply little-endian (starting with the least significant byte), i.e., the lowest byte comes first in the memory cell allocated for the variable, then follows the byte with higher bits, and so on. The alternative big-endian (starting with the highest digit, the most significant byte) is widely used on the Internet. In this case, the first byte in the memory cell is the byte with the high bits, and the last byte is the low bit. It is this order that is similar to how we write numbers "from left to right" in ordinary life. For example, the value 1234 starts with 1 and stands for thousands, followed by a 2 for hundreds, a 3 for tens, and the last 4 is just four (low order). + +Let's see the default byte order in MQL5. To do this, we will use the script MathSwap.mq5. + +It describes a concatenation pattern that allows you to convert an integer to an array of bytes: + +``` +template +union ByteOverlay +{ +   T value; +   uchar bytes[sizeof(T)]; +   ByteOverlay(const T v) : value(v) { } +   void operator=(const T v) { value = v; } +}; + +``` + +This code allows you to visually divide the number into bytes and enumerate them with indices from the array. + +In OnStart, we describe the uint variable with the value 0x12345678 (note that the digits are hexadecimal; in such a notation they exactly correspond to byte boundaries: every 2 digits is a separate byte). Let's convert the number to an array and output it to the log. + +``` +void OnStart() +{ +   const uint ui = 0x12345678; +   ByteOverlay bo(ui); +   ArrayPrint(bo.bytes); // 120  86  52  18 <==> 0x78 0x56 0x34 0x12 +   ... + +``` + +The ArrayPrint function can't print numbers in hexadecimal, so we see their decimal representation, but it's easy to convert them to base 16 and make sure they match the original bytes. Visually, they go in reverse order: i.e., under the 0th index in the array is 0x78, and then 0x56, 0x34 and 0x12. Obviously, this order starts with the least-significant byte (indeed, we are in the Windows environment). + +Now let's get familiar with the function MathSwap, which MQL5 provides to change the byte order. + +integer MathSwap(integer value) + +The function returns an integer in which the byte order of the passed argument is reversed. The function takes parameters of type ushort/uint/ulong (i.e. 2, 4, 8 bytes in size). + +Let's try the function in action: + +``` +   const uint ui = 0x12345678; +   PrintFormat("%I32X -> %I32X", ui, MathSwap(ui)); +   const ulong ul = 0x0123456789ABCDEF; +   PrintFormat("%I64X -> %I64X", ul, MathSwap(ul)); + +``` + +Here is the result: + +``` +   12345678 -> 78563412 +   123456789ABCDEF -> EFCDAB8967452301 + +``` + +Let's try to log an array of bytes after converting the value 0x12345678 with MathSwap: + +``` +   bo = MathSwap(ui);    // put the result of MathSwap into ByteOverlay +   ArrayPrint(bo.bytes); //  18  52  86 120 <==> 0x12 0x34 0x56 0x78 + +``` + +In a byte with index 0, where it used to be 0x78, there is now 0x12, and in elements with other numbers, the values are also exchanged. diff --git a/skills/mql5/references/book/03-common/0175-common-files.md b/skills/mql5/references/book/03-common/0175-common-files.md new file mode 100644 index 0000000..5090c3f --- /dev/null +++ b/skills/mql5/references/book/03-common/0175-common-files.md @@ -0,0 +1,86 @@ +# Working with files + +It is difficult to find a program that does not use data input-output. We already know that MQL programs can receive settings via [input variables](/en/book/basis/variables/input_variables) and output information to the log as we used the latter in almost all test scripts. But in most cases, this is not enough. + +For example, quite a significant part of program customization includes amounts of data that cannot be accommodated in the input parameters. A program may need to be integrated with some external analytical tools, i.e., uploading market information in a standard or specialized format, processing and then loading it into the terminal in a new form, in particular, as trading signals, a set of neural network weights or decision tree coefficients. Furthermore, it can be convenient to maintain a separate log for an MQL program. + +The file subsystem provides the most universal opportunities for such tasks. The MQL5 API provides a wide range of functions for working with files, including functions to create, delete, search, write, and read the files. We will study all this in this chapter. + +All file operations in MQL5 are limited to a special area on the disk, which is called a sandbox. This is done for security reasons so that no MQL program can be used for malicious purposes and harm your computer or operating system. + +Advanced users can avoid this limitation using special measures, which we will discuss later. But this should only be done in exceptional cases while observing precautions and accepting all responsibility. + +For each instance of the terminal installed on the computer, the sandbox root directory is located at /MQL5/Files/. From the MetaEditor, you can open the data folder using the command File -> Open Data Folder. If you have sufficient access rights on the computer, this directory is usually the same place where the terminal is installed. If you do not have the required permissions, the path will look like this: + +``` +X:/Users//AppData/Roaming/MetaQuotes/Terminal//MQL5/Files/ + +``` + +Here X is a drive letter where the system is installed, is the Windows user login, is a unique identifier of the terminal instance. The Users folder also has an alias "Documents and Settings". + +Please note that in the case of a remote connection to a computer via RDP (Remote Desktop Protocol), the terminal will always use the Roaming directory and its subdirectories even if you have administrator rights. + +Let's recall that the MQL5 folder in the data directory is the place where all MQL programs are stored: both their source codes and compiled ex5 files. Each type of MQL program, including indicators, Expert Advisors, scripts, and others, has a dedicated subfolder in the MQL5 folder. So the Files folder for working files is next to them. + +In addition to this individual sandbox of each copy of the terminal on the computer, there is a common, shared sandbox for all terminals: they can communicate through it. The path to it runs through the home folder of the Windows user and may differ depending on the version of the operating system. For example, in standard installations of Windows 7, 8, and 10, it looks like this: + +``` +X:/Users//AppData/Roaming/MetaQuotes/Terminal/Common/Files/ + +``` + +Again, the folder can be easily accessed through MetaTrader: run the command File -> Open Shared Data Folder, and you will be inside the Common folder. + +Some types of MQL programs (Expert Advisors and indicators) can be executed not only in the terminal but also in the tester. When running in it, the shared sandbox remains accessible, and instead of a single instance sandbox, a folder inside the test agent is used. As a rule, it looks like: + +``` +X://Tester/Agent-IP-port/MQL5/Files/ + +``` + +This may not be visible in the MQL program itself, i.e., all file functions work in exactly the same way. However, from the user's point of view, it may seem that there is some kind of problem. For example, if the program saves the results of its work to a file, it will be deleted in the tester's agent folder after the run is completed (as if the file had never been created). This routine approach is designed to prevent potentially valuable data of one program from leaking into another program that can be tested on the same agent some time later (especially since agents can be shared). Other technologies are provided for transferring files to agents and returning results from agents to the terminal, which we will discuss in the fifth Part of the book. + +To get around the sandbox limitation, you can use Windows' ability to assign symbolic links to file system objects. In our case, the connections (junction) are best suited for redirecting access to folders on the local computer. They are created using the following command (meaning the Windows command line): + +``` +mklink /J new_name existing_target + +``` + +The parameter new_name is the name of the new virtual folder that will point to the real folder existing_target. + +To create connections to external folders outside the sandbox, it is recommended to create a dedicated folder inside MQL5/Files, for example, Links. Then, having entered it, you can execute the above command by selecting new_name and substituting the real path outside the sandbox as existing_target. For example, the following command will create in the folder Links a new link named Settings, which will provide access to the MQL5/Presets folder: + +``` +mklink /J Settings "..\..\Presets\" + +``` + +The relative path "..\..\" assumes that the command is executed in the specified MQL5/Files/Links folder. A combination of two dots ".." indicates the transition from the current folder to the parent. Specified twice, this combination instructs to go up the path hierarchy twice. As a result, the target folder (existing_target) will be generated as MQL5/Presets. But in the existing_target parameter, you can also specify an absolute path. + +You can delete symbolic links like regular files (but, of course, you should first make sure that it is the folder with the arrow icon in its lower left corner that is being deleted, i.e. the link, and not the original folder). It is recommended to do this immediately, as soon as you no longer need to go beyond the sandbox. The fact is that the created virtual folders become available to all MQL programs, not just yours, and it is not known how other people's programs can use the additional freedom. + +Many sections of the chapter deal with file names. They act as file system element identifiers and have similar rules, including some restrictions. + +Please note that the file name cannot contain some characters that play special roles in the file system ('<', '>', '/', '\\', '"', ':', '|', '* ', '?'), as well as any characters with codes from 0 to 31 inclusive. + +The following file names are also reserved for special use in the operating system and cannot be used: CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9. + +It should be noted that the Windows file system does not see the fundamental difference between letters in different cases, so names like "Name", "NAME", and "name" refer to the same element. + +Windows allows both backslashes '\\' and forward slashes '/' to be used as a separator character between path components (subfolders and files). However, the backslash needs to be screened (that is, actually written twice) in MQL5 strings, because the '\' character itself is special: it is used to construct control character sequences, such as '\r', '\n', '\t' and others (see section [Character types](/en/book/basis/builtin_types/characters)). For example, the following paths are equivalent: "MQL5Book/file.txt" and "MQL5Book\\file.txt". + +The dot character '.' serves as a separator between the name and the extension. If a file system element has multiple dots in its identifier, then the extension is the fragment to the right of the rightmost dot, and everything to the left of it is the name. The title (before the dot) or extension (after the dot) can be empty. For example, the file name without an extension is "text", and the file without a name (only with the extension) is ".txt". + +The total length of the path and file name in Windows has limitations. At the same time, to manage files in MQL5, it should be taken into account that the path to the sandbox will be added to their path and name, i.e., even less space will be allocated for the names of file objects in MQL function calls. By default, the overall length limit is the system constant MAX_PATH, which is equal 260. Starting from Windows 10 (build 1607), you can increase this limit to 32767. To do this, you need to save the following text in a .reg file and run it by adding it to the Windows Registry. + +  + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem] + +"LongPathsEnabled"=dword:00000001 + +  + +For other versions of Windows, you can use workarounds from the command line. In particular, you can shorten the path using the connections discussed above (by creating a virtual folder with a short path). You can also use the shell command -subst, For example, subst z: c:\very\long\path (see Windows Help for details). diff --git a/skills/mql5/references/book/03-common/0176-common-files-files-modes-bin-txt.md b/skills/mql5/references/book/03-common/0176-common-files-files-modes-bin-txt.md new file mode 100644 index 0000000..2815292 --- /dev/null +++ b/skills/mql5/references/book/03-common/0176-common-files-files-modes-bin-txt.md @@ -0,0 +1,57 @@ +# Information storage methods: text and binary + +We have already seen in many previous sections that the same information can be represented in textual and binary forms. For example, numbers of int, long, and double formats, date and time (datetime) and colors (color) are stored in memory as a sequence of bytes of a certain length. This method is compact and is better for computer interpretation, but it is more convenient for a human to analyze information in a text form, although it takes longer. Therefore, we paid much attention to [converting numbers to strings and vice versa](/en/book/common/conversions/conversions_numbers), and to [functions for working with strings](/en/book/common/strings). + +At the file level, the division into the binary and textual representation of data is also preserved. A binary file is designed to store data in the same internal representation that is used in memory. The text file contains a string representation. + +Text files are commonly used for standard formats such as CSV (Comma Separated Values), JSON (JavaScript Object Notation), XML (Extensible Markup Language), HTML (HyperText Markup Language). + +Binary files, of course, also have standard formats for many applications, in particular for images (PNG, GIF, JPG, BMP), sounds (WAV, MP3), or compressed archives (ZIP). However, the binary format initially assumes greater protection and low-level work with data, and therefore is more often used to solve internal problems, when only storage efficiency and data availability for a specific program are important. In other words, objects of any applied structures and classes can easily save and restore their state in a binary file, actually making a memory impression and not worrying about compatibility with any standard. + +In theory, we could manually convert the data to strings when writing to a binary file and then convert it back from strings to numbers (or structures, or arrays) when reading the file. This would be similar to what the text file mode automatically provides but would require additional effort. The text file mode saves us from such a routine. Moreover, the MQL5 file subsystem implicitly performs several optional but important operations that are necessary when working with text. + +First, the concept of text is based on some general rules of using delimiter characters. In particular, it is assumed that all texts consist of strings. This way it is more convenient to read and analyze them algorithmically. Therefore, there are special characters that separate one string from another. + +Here we are faced with the first difficulties associated with the fact that different operating systems accept different combinations of these characters. In Windows, the line separator is the sequence of two characters '\r\n' (either as hexadecimal codes: 0xD 0xA, or as the name CRLF, which stands for Carriage Return and Line Feed). In Unix and Linux, the single character '\n' is the standard, but some versions and programs under MacOS may use the single character '\r'. + +Although MetaTrader 5 runs under Windows, we have no guarantee that any resulting text file will not be saved with unusual separators. If we were to read it in binary mode and check for delimiters ourselves to form strings, these discrepancies would require specific handling. Here the text mode of file operation in MQL5 comes to the rescue: it automatically normalizes line breaks when reading and writing. + +MQL5 might not fix line breaks for all cases. In particular, a single character '\r' will not be interpreted as '\r\n' when reading a text file, while a single '\n' is correctly interpreted as '\r\n'. + +Secondly, strings can be stored in memory in multiple representations. By default, string (type [string](/en/book/basis/builtin_types/strings)) in MQL5 consists of two-byte [characters](/en/book/basis/builtin_types/characters). This provides support for the universal Unicode encoding, which is nice because it includes all national scripts. However, in many cases, such universality is not required (for example, when storing numbers or messages in English), in which case it is more efficient to use strings of single-byte characters in the ANSI encoding. The MQL5 API functions allow you to choose the preferred way of writing strings in text mode into files. But if we control writing in our MQL program, we can guarantee the validity and reliability of switching from Unicode to single-byte characters. In this case, when integrating with some external software or web service, the ANSI code page in its files can be any. In this regard, the following point arises. + +Thirdly, due to the presence of many different languages, you need to be prepared for texts in various ANSI encodings. Without the correct interpretation of the encoding, the text can be written or read with distortions, or even become unreadable. We saw it in the section [Working with symbols and code pages](/en/book/common/strings/strings_codepages). This is why file functions already include means for correct character processing: it is enough to specify the desired or expected encoding in the parameters. The choice of encoding is described in more detail in a [separate section](/en/book/common/files/files_txt_codepage). + +And finally, the text mode has built-in support for the well-known CSV format. Since trading often requires tabular data, CSV is well suited for this. In a text file in CSV mode, the MQL5 API functions process not only delimiters for wrapping lines of text but also an additional delimiter for the border of columns (fields in each row of the table). This is usually a tab character '\t', a comma ',' or a semicolon ';'. For example, here is what a CSV file with Forex news looks like ( a comma-separated fragment is shown): + +``` +Title,Country,Date,Time,Impact,Forecast,Previous +Bank Holiday,JPY,08-09-2021,12:00am,Holiday,, +CPI y/y,CNY,08-09-2021,1:30am,Low,0.8%,1.1% +PPI y/y,CNY,08-09-2021,1:30am,Low,8.6%,8.8% +Unemployment Rate,CHF,08-09-2021,5:45am,Low,3.0%,3.1% +German Trade Balance,EUR,08-09-2021,6:00am,Low,13.9B,12.6B +Sentix Investor Confidence,EUR,08-09-2021,8:30am,Low,29.2,29.8 +JOLTS Job Openings,USD,08-09-2021,2:00pm,Medium,9.27M,9.21M +FOMC Member Bostic Speaks,USD,08-09-2021,2:00pm,Medium,, +FOMC Member Barkin Speaks,USD,08-09-2021,4:00pm,Medium,, +BRC Retail Sales Monitor y/y,GBP,08-09-2021,11:01pm,Low,4.9%,6.7% +Current Account,JPY,08-09-2021,11:50pm,Low,1.71T,1.87T + +``` + +And here it is, for clarity, in the form of a table: + +| Title | Country | Date | Time | Impact | Forecast | Previous | +| --- | --- | --- | --- | --- | --- | --- | +| Bank Holiday | JPY | 08-09-2021 | 12:00am | Holiday | | | +| CPI y/y | CNY | 08-09-2021 | 1:30am | Low | 0.8% | 1.1% | +| PPI y/y | CNY | 08-09-2021 | 1:30am | Low | 8.6% | 8.8% | +| Unemployment Rate | CHF | 08-09-2021 | 5:45am | Low | 3.0% | 3.1% | +| German Trade Balance | EUR | 08-09-2021 | 6:00am | Low | 13.9B | 12.6B | +| Sentix Investor Confidence | EUR | 08-09-2021 | 8:30am | Low | 29.2 | 29.8 | +| JOLTS Job Openings | USD | 08-09-2021 | 2:00pm | Medium | 9.27M | 9.21M | +| FOMC Member Bostic Speaks | USD | 08-09-2021 | 2:00pm | Medium | | | +| FOMC Member Barkin Speaks | USD | 08-09-2021 | 4:00pm | Medium | | | +| BRC Retail Sales Monitor y/y | GBP | 08-09-2021 | 11:01pm | Low | 4.9% | 6.7% | +| Current Account | JPY | 08-09-2021 | 11:50pm | Low | 1.71T | 1.87T | diff --git a/skills/mql5/references/book/03-common/0177-common-files-files-save-load.md b/skills/mql5/references/book/03-common/0177-common-files-files-save-load.md new file mode 100644 index 0000000..818bbc6 --- /dev/null +++ b/skills/mql5/references/book/03-common/0177-common-files-files-save-load.md @@ -0,0 +1,176 @@ +# Writing and reading files in simplified mode + +Among the MQL5 file functions that are intended for writing and reading data, there is a division into 2 unequal groups. The first of these includes two functions: FileSave and FileLoad, which allow you to write or read data in binary mode in a single function call. On the one hand, this approach has an undeniable advantage, the simplicity, but on the other hand, it has some limitations (more on those below). In the second large group, all file functions are used differently: it is required to call several of them sequentially in order to perform a logically complete read or write operation. This seems more complex, but it provides flexibility and control over the process. The functions of the second group operate with special integers — file descriptors, which should be obtained using the FileOpen function (see the [next section](/en/book/common/files/files_open_close)). + +Let's view the formal description of these two functions, and then consider their example (FileSaveLoad.mq5). + +bool FileSave(const string filename, const void &data[], const int flag = 0) + +The function writes all elements of the passed data array to a binary file named filename. The filename parameter may contain not only the file name but also the names of folders of several levels of nesting: the function will create the specified folders if they do not already exist. If the file exists, it will be overwritten (unless occupied by another program). + +As the data parameter, an array of any built-in types can be passed, except for strings. It can also be an array of simple structures containing fields of built-in types with the exception of strings, dynamic arrays, and pointers. Classes are also not supported. + +The flag parameter may, if necessary, contain the predefined constant FILE_COMMON, which means creating and writing a file to the common data directory of all terminals (Common/Files/). If the flag is not specified (which corresponds to the default value of 0), then the file is written to the regular data directory (if the MQL program is running in the terminal) or to the testing agent directory (if it happens in the tester). In the last two cases, the MQL5/Files/ sandbox is used inside the directory, as described at the beginning of the chapter. + +The function returns an indication of operation success (true) or error (false). + +long FileLoad(const string filename, void &data[], const int flag = 0) + +The function reads the entire contents of a binary file filename to the specified data array. The file name may include a folder hierarchy within the MQL5/Files or Common/Files sandbox. + +The data array must be of any built-in type except string, or a simple structure type (see above). + +The flag parameter controls the selection of the directory where the file is searched and opened: by default (with a value of 0) it is the standard sandbox, but if the value FILE_COMMON is set, then it is the sandbox shared by all terminals. + +The function returns the number of items read, or -1 on error. + +Note that the data from the file is read in blocks of one array element. If the file size is not a multiple of the element size, then the remaining data is skipped (not read). For example, if the file size is 10 bytes, reading it into an array of double type (sizeof(double)=8) will result in only 8 bytes actually being loaded, i.e. 1 element (and the function will return 1). The remaining 2 bytes at the end of the file will be ignored. + +In the FileSaveLoad.mq5 script we define two structures for tests. + +``` +struct Pair +{ +   short x, y; +}; +   +struct Simple +{ +   double d; +   int i; +   datetime t; +   color c; +   uchar a[10]; // fixed size array allowed +   bool b; +   Pair p;      // compound fields (nested simple structures) are also allowed +    +   // strings and dynamic arrays will cause a compilation error when used +   // FileSave/FileLoad: structures or classes containing objects are not allowed +   // string s; +   // uchar a[]; +    +   // pointers are also not supported +   // void *ptr; +}; + +``` + +The Simple structure contains fields of most allowed types, as well as a composite field with the Pair structure type. In the OnStart function, we fill in a small array of the Simple type. + +``` +void OnStart() +{ +   Simple write[] = +   { +      {+1.0, -1, D'2021.01.01', clrBlue, {'a'}, true, {1000, 16000}}, +      {-1.0, -2, D'2021.01.01', clrRed,  {'b'}, true, {1000, 16000}}, +   }; +   ... + +``` + +We will select the file for writing data together with the MQL5Book subfolder so that our experiments do not mix with your working files: + +``` +   const string filename = "MQL5Book/rawdata"; + +``` + +Let's write an array to a file, read it into another array, and compare them. + +``` +   PRT(FileSave(filename, write/*, FILE_COMMON*/)); // true +    +   Simple read[]; +   PRT(FileLoad(filename, read/*, FILE_COMMON*/)); // 2 +    +   PRT(ArrayCompare(write, read)); // 0 + +``` + +FileLoad returned 2, i.e., 2 elements (2 structures) were read. If the comparison result is 0, that means that the data matched. You can open the folder in your favorite file manager MQL5/Files/MQL5Book and make sure that there is the 'rawdata' file (it is not recommended to view its contents using a text editor, we suggest using a viewer that supports binary mode). + +Further in the script, we convert the read array of structures into bytes and output them to the log in the form of hexadecimal codes. This is a kind of memory dump, and it allows you to understand what binary files are. + +``` +   uchar bytes[]; +   for(int i = 0; i < ArraySize(read); ++i) +   { +      uchar temp[]; +      PRT(StructToCharArray(read[i], temp)); +      ArrayCopy(bytes, temp, ArraySize(bytes)); +   } +   ByteArrayPrint(bytes); + +``` + +Result: + +``` + [00] 00 | 00 | 00 | 00 | 00 | 00 | F0 | 3F | FF | FF | FF | FF | 00 | 66 | EE | 5F |  + [16] 00 | 00 | 00 | 00 | 00 | 00 | FF | 00 | 61 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |  + [32] 00 | 00 | 01 | E8 | 03 | 80 | 3E | 00 | 00 | 00 | 00 | 00 | 00 | F0 | BF | FE |  + [48] FF | FF | FF | 00 | 66 | EE | 5F | 00 | 00 | 00 | 00 | FF | 00 | 00 | 00 | 62 |  + [64] 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 01 | E8 | 03 | 80 | 3E |  + +``` + +Because the built-in ArrayPrint function can't print in hexadecimal format, we had to develop our own function ByteArrayPrint (here we will not give its source code, see the attached file). + +Next, let's remember that FileLoad is able to load data into an array of any type, so we will read the same file using it directly into an array of bytes. + +``` +   uchar bytes2[]; +   PRT(FileLoad(filename, bytes2/*, FILE_COMMON*/)); // 78,  39 * 2 +   PRT(ArrayCompare(bytes, bytes2)); // 0, equality + +``` + +A successful comparison of two byte arrays shows that FileLoad can operate with raw data from the file in an arbitrary way, in which it is instructed (there is no information in the file that it stores an array of Simple structures). + +It is important to note here that since the byte type has a minimum size (1), it is a multiple of any file size. Therefore, any file is always read into a byte array without a remainder. Here the FileLoad function has returned the number 78 (the number of elements is equal to the number of bytes). This is the size of the file (two structures of 39 bytes each). + +Basically, the ability of FileLoad to interpret data for any type requires care and checks on the part of the programmer. In particular, further in the script, we read the same file into an array of structures MqlDateTime. This, of course, is wrong, but it works without errors. + +``` +   MqlDateTime mdt[]; +   PRT(sizeof(MqlDateTime)); // 32 +   PRT(FileLoad(filename, mdt)); // 2 + // attention: 14 bytes left unread +   ArrayPrint(mdt); + +``` + +The result contains a meaningless set of numbers: + +``` +        [year]      [mon] [day]     [hour]    [min]    [sec] [day_of_week] [day_of_year] +[0]          0 1072693248    -1 1609459200        0 16711680            97             0 +[1] -402587648    4096003     0  -20975616 16777215  6286950     -16777216    1644167168 + +``` + +Because the size of MqlDateTime is 32, then only two such structures fit in a 78-byte file, and 14 more bytes remain superfluous. The presence of a residue indicates a problem. But even if there is no residue, this does not guarantee the meaningfulness of the operation performed, because two different sizes can, purely by chance, fit an integer (but different) number of times in the length of the file. Moreover, two structures that are different in meaning can have the same size, but this does not mean that they should be written and read from one to the other. + +Not surprisingly, the log of the array of structures MqlDateTime shows strange values, since it was, in fact, a completely different data type. + +To make reading somewhat more careful, the script implements an analog of the FileLoad function — MyFileLoad. We will analyze this function in detail, as well as its pair MyFileSave, in the following sections, when learning new file functions and using them to model the internal structure FileSave/FileLoad. In the meantime, just note that in our version, we can check for the presence of an unread remainder in the file and display a warning. + +To conclude, let's look at a couple more potential errors demonstrated in the script. + +``` +   /* +  // compilation error, string type not supported here +   string texts[]; +   FileSave("any", texts); // parameter conversion not allowed +   */ +    +   double data[]; +   PRT(FileLoad("any", data)); // -1 +   PRT(_LastError); // 5004, ERR_CANNOT_OPEN_FILE + +``` + +The first one happens at compile time (which is why the code block is commented out) because string arrays are not allowed. + +The second is to read a non-existent file, which is why FileLoad returns -1. An explanatory error code can be easily obtained using GetLastError (or [_LastError](/en/book/common/environment/env_last_error)). diff --git a/skills/mql5/references/book/03-common/0178-common-files-files-open-close.md b/skills/mql5/references/book/03-common/0178-common-files-files-open-close.md new file mode 100644 index 0000000..ca4cf68 --- /dev/null +++ b/skills/mql5/references/book/03-common/0178-common-files-files-open-close.md @@ -0,0 +1,221 @@ +# Opening and closing files + +To write and read data from a file, most MQL5 functions require that the file be opened first. For this purpose, there is the FileOpen function. After performing the required operations, the open file should be closed using the FileClose function. The fact is that an open file may, depending on the applied options, be blocked for access from other programs. In addition, file operations are buffered in memory (cache) for performance reasons, and without closing the file, new data may not be physically uploaded to it for some time. This is especially critical if the data being written is waiting for an external program (for example, when integrating an MQL program with other systems). We learn about an alternative way to flush the buffer to disk from the description of the [FileFlush](/en/book/common/files/files_flush) function. + +A special integer referred to as the descriptor is associated with an open file in an MQL program. It is returned by the FileOpen function. All operations related to accessing or modifying the internal contents of a file require this identifier to be specified in the corresponding API functions. Those functions that operate on the entire file (copy, delete, move, check for existence) do not require a descriptor. You do not need to open the file to perform these steps. + +int FileOpen(const string filename, int flags, const short delimiter = '\t', uint codepage = CP_ACP) + +int FileOpen(const string filename, int flags, const string delimiter, uint codepage = CP_ACP) + +The function opens a file with the specified name, in the mode specified by the flags parameter. The filename parameter may contain subfolders before the actual file name. In this case, if the file is opened for writing and the required folder hierarchy does not yet exist, it will be created. + +The flags parameter must contain a combination of constants describing the required mode of working with the file. The combination is performed using the operations of [bitwise OR](/en/book/basis/expressions/operators_bitwise). Below is a table of available constants. + +| Identifier | Value | Description | +| --- | --- | --- | +| FILE_READ | 1 | The file is opened for reading | +| FILE_WRITE | 2 | The file is opened for writing | +| FILE_BIN | 4 | Binary read-write mode, no data conversion from string to string | +| FILE_CSV | 8 | File of CSV type; the data being written is converted to text of the appropriate type (Unicode or ANSI, see below), and when reading, the reverse conversion is performed from the text to the required type (specified in the reading function); one CSV record is a single line of text, delimited by newline characters (usually CRLF); inside the CSV record, the elements are separated by a delimiter character (parameter delimiter ); | +| FILE_TXT | 16 | Plain text file, similar to CSV mode, but a delimiter character is not used (the value of the parameter delimiter is ignored) | +| FILE_ANSI | 32 | ANSI type strings (single-byte characters) | +| FILE_UNICODE | 64 | Unicode type strings (double-byte characters) | +| FILE_SHARE_READ | 128 | Shared read access from several programs | +| FILE_SHARE_WRITE | 256 | Shared writing access by multiple programs | +| FILE_REWRITE | 512 | Permission to overwrite a file (if it already exists) in functions FileCopy and FileMove | +| FILE_COMMON | 4096 | File location in the shared folder of all client terminals /Terminal/Common/Files (the flag is used when opening files (FileOpen), copying files (FileCopy, FileMove) and checking the existence of files ( FileIsExist )) | + +When opening a file, one of the FILE_WRITE, FILE_READ flags or their combination must be specified. + +The FILE_SHARE_READ and FILE_SHARE_WRITE flags do not replace or cancel the need to specify the FILE_READ and FILE_WRITE flags. + +The MQL program execution environment always buffers files for reading, which is equivalent to implicitly adding the FILE_READ flag. Because of this, FILE_SHARE_READ should always be used to work properly with shared files (even if another process is known to have a write-only file open). + +If none of the FILE_CSV, FILE_BIN, FILE_TXT flags is specified, FILE_CSV is assumed as the highest priority. If more than one of these three flags is specified, the highest priority passed is applied (they are listed above in descending order of priority). + +For text files, the default mode is FILE_UNICODE. + +The delimiter parameter affecting only CSV, could be of type ushort or string. In the second case, if the length of the string is greater than 1, only its first character will be used. + +The codepage parameter only affects files opened in text mode (FILE_TXT or FILE_CSV), and only if FILE_ANSI mode is selected for strings. If the strings are stored in Unicode (FILE_UNICODE), the code page is not important. + +If successful, the function returns a file descriptor, a positive integer. It is unique only within a particular MQL program; it makes no sense to share it with other programs. For further work with the file, the descriptor is passed to calls to other functions. + +On error, the result is INVALID_HANDLE (-1). The essence of the error should be clarified from the code returned by the [GetLastError](/en/book/common/environment/env_last_error) function. + +All operating mode settings made at the time the file is opened remain unchanged for as long as the file is open. If it becomes necessary to change the mode, the file should be closed and reopened with the new parameters. + +For each open file, the MQL program execution environment maintains an internal pointer, i.e. the current position within the file. Immediately after opening the file, the pointer is set to the beginning (position 0). In the process of writing or reading, the position is shifted appropriately, according to the amount of data transmitted or received from various file functions. It is also possible to directly influence the position (move back or forward). All these opportunities will be discussed in the following sections. + +FILE_READ and FILE_WRITE in various combinations allow you to achieve several scenarios: + +- FILE_READ — open a file only if it exists; otherwise, the function returns an error and no new file is created. +- FILE_WRITE — creating a new file if it does not already exist, or opening an existing file, and its contents are cleared and the size is reset to zero. +- FILE_READ|FILE_WRITE — open an existing file with all its contents or create a new file if it does not already exist. + +As you can see, some scenarios are inaccessible only due to flags. In particular, you cannot open a file for writing only if it already exists. This can be achieved using additional functions, for example, [FileIsExist](/en/book/common/files/files_exist_delete). Also, it will not be possible to "automatically" reset a file opened for a combination of reading and writing: in this case, MQL5 always leaves the contents. + +To append data to a file, one must not only open the file in FILE_READ|FILE_WRITE mode, but also move the current position within the file to its end by calling [FileSeek](/en/book/common/files/files_cursor). + +The correct description of the shared access to the file is a prerequisite for successful execution of File Open. This aspect is managed as follows. + +- If neither of the FILE_SHARE_READ and FILE_SHARE_WRITE flags is specified, then the current program gets exclusive access to the file if it opens it first. If the same file has already been opened by someone before (by another program,or by the same program), the function call will fail. +- When the FILE_SHARE_READ flag is set, the program allows subsequent requests to open the same file for reading. If at the time of the function call the file is already open for reading by another or the same program, and this flag is not set, the function will fail. +- When the FILE_SHARE_WRITE flag is set, the program allows subsequent requests to open the same file for writing. If at the time of the function call the file is already open for writing by another or the same program, and this flag is not set, the function will fail. + +Access sharing is checked not only in relation to other MQL programs or processes external to MetaTrader 5, but also in relation to the same MQL program if it reopens the file. + +Thus, the least conflicting mode implies that both flags are specified, but it still does not guarantee that the file will be opened if someone has already been issued a descriptor to it with no sharing. However, more stringent rules should be followed depending on the planned reads or writes. + +For example, when opening a file for reading, it makes sense to leave the opportunity for others to read it. Additionally, you can probably allow others to write to it, if it is a file that is being replenished (for example, a journal). However, when opening a file for writing, it is hardly worth leaving write access to others: this would lead to unpredictable data overlay. + +void FileClose(int handle) + +The function closes a previously opened file by its handle. + +After the file is closed, its handle in the program becomes invalid: an attempt to call any file function on it will result in an error. However, you can use the same variable to store a different handle if you reopen the same or a different file. + +When the program terminates, open files are forcibly closed, and the write buffer, if it is not empty, is written to disk. However, it is recommended to close files explicitly. + +Closing a file when you're finished working with it is an important rule to follow. This is due not only to the caching of the information being written, which may remain in RAM for some time and not saved to disk (as already mentioned above), if the file is not closed. In addition, an open file consumes some internal resource of the operating system, and we are not talking about disk space. The number of simultaneously open files is limited (maybe several hundred or thousands depending on Windows settings). If many programs keep a large number of files open, this limit may be reached and attempts to open new files will fail. + +In this regard, it is desirable to protect yourself from the possible loss of descriptors using a wrapper class that would open a file and receive a descriptor when creating an object, and the descriptor would be released and the file closed automatically in the destructor. + +We will create a wrapper class after testing the pure FileOpen and FileClose functions. + +But before diving into file specifics, let's prepare a new version of the macro to illustrate an output of our functions to the call log. The new version was required because, until now, macros like PRT and PRTS (used in previous sections) "absorbed" function return values during printing. For example, we wrote: + +``` +PRT(FileLoad(filename, read)); + +``` + +Here the result of the FileLoad call is sent to the log, but it is not possible to get it in the calling string of code. To tell the truth, we did not need it. But now the FileOpen function will return a file descriptor, and should be stored in a variable for further manipulation of the file. + +There are two problems with the old macros. First, they are based on the function Print, which consumes the passed data (sending it to the log) but does not itself return anything. Second, any value for a variable with a result can only be obtained from an expression, and a Print call cannot be made a part of an expression due to the fact that it has the type void. + +To solve these problems, we need a print helper function that returns a printable value. And we will pack its call into a new PRTF macro: + +``` +#include  +   +#define PRTF(A) ResultPrint(#A, (A)) +   +template +T ResultPrint(const string s, const T retval = 0) +{ +   const string err = E2S(_LastError) + "(" + (string)_LastError + ")"; +   Print(s, "=", retval, " / ", (_LastError == 0 ? "ok" : err)); + ResetLastError();// clear the error flag for the next call +   return retval; +} + +``` + +Using the '#' magic string conversion operator, we get a detailed descriptor of the code fragment (expression A) that is passed as the first argument to ResultPrint. The expression itself (the macro argument) is evaluated (if there is a function, it is called), and its result is passed as the second argument to ResultPrint. Next, the usual Print function comes into play, and finally, the same result is returned to the calling code. + +In order not to look into the Help for decoding error codes, an E2S macro was prepared that uses the MQL_ERROR enumeration with all MQL5 errors. It can be found in the header file MQL5/Include/MQL5Book/MqlError.mqh. The new macro and the ResultPrint function are defined in the PRTF.mqh file, next to the test scripts. + +In the FileOpenClose.mq5 script, let's try to open different files, and, in particular, the same file will open several times in parallel. This is usually avoided in real programs. A single handle to a particular file in a program instance is sufficient for most tasks. + +One of the files, MQL5Book/rawdata, must already exist since it was created by a script from the section [Writing and reading files in simplified mode](/en/book/common/files/files_save_load). Another file will be created during the test. + +We will choose the file type FILE_BIN. working with FILE_TXT or FILE_CSV would be similar at this stage. + +Let's reserve an array for file descriptors so that at the end of the script we close all files at once. + +First, let's open MQL5Book/rawdata in reading mode without access sharing. Assuming that the file is not in use by any third party application, we can expect the handle to be successfully received. + +``` +void OnStart() +{ +   int ha[4] = {}; // array for test file handles  +    +   // this file must exist after running FileSaveLoad.mq5 +   const string rawdata = "MQL5Book/rawdata"; +   ha[0] = PRTF(FileOpen(rawdata, FILE_BIN | FILE_READ)); // 1 / ok + +``` + +If we try to open the same file again, we will encounter an error because neither the first nor the second call allows sharing. + +``` + ha[1] = PRTF(FileOpen(rawdata, FILE_BIN | FILE_READ)); // -1 / CANNOT_OPEN_FILE(5004) + +``` + +Let's close the first handle, open the file again, but with shared read permissions, and make sure that reopening now works (although it also needs to allow shared reading): + +``` +   FileClose(ha[0]); +   ha[0] = PRTF(FileOpen(rawdata, FILE_BIN | FILE_READ | FILE_SHARE_READ)); // 1 / ok +   ha[1] = PRTF(FileOpen(rawdata, FILE_BIN | FILE_READ | FILE_SHARE_READ)); // 2 / ok + +``` + +Opening a file for writing (FILE_WRITE) will not work, because the two previous calls of FileOpen only allow FILE_SHARE_READ. + +``` +   ha[2] = PRTF(FileOpen(rawdata, FILE_BIN | FILE_READ | FILE_WRITE | FILE_SHARE_READ)); +   // -1 / CANNOT_OPEN_FILE(5004) + +``` + +Now let's try to create a new file MQL5Book/newdata. If you open it as read-only, the file will not be created. + +``` +   const string newdata = "MQL5Book/newdata"; +   ha[3] = PRTF(FileOpen(newdata, FILE_BIN | FILE_READ)); +   // -1 / CANNOT_OPEN_FILE(5004) + +``` + +To create a file, you must specify the FILE_WRITE mode (the presence of FILE_READ is not critical here, but it makes the call more universal: as we remember, in this combination, the instruction guarantees that either the old file will be opened, if it exists, or a new one will be created). + +``` +   ha[3] = PRTF(FileOpen(newdata, FILE_BIN | FILE_READ | FILE_WRITE)); // 3 / ok + +``` + +Let's try to write something to a new file using the function [FileSave](/en/book/common/files/files_save_load) known to us. It acts as an "external player", since it works with the file bypassing our descriptor, in much the same way as it could be done by another MQL program or a third-party application. + +``` +   long x[1] = {0x123456789ABCDEF0}; +   PRTF(FileSave(newdata, x)); // false + +``` + +This call fails because the handle was opened without sharing permissions. Close and reopen the file with maximum "permissions". + +``` +   FileClose(ha[3]); +   ha[3] = PRTF(FileOpen(newdata,  +      FILE_BIN | FILE_READ | FILE_WRITE | FILE_SHARE_READ | FILE_SHARE_WRITE)); // 3 / ok + +``` + +This time FileSave works as expected. + +``` +   PRTF(FileSave(newdata, x)); // true + +``` + +You can look in the folder MQL5/Files/MQL5Book/ and find there the newdata file, 8 bytes long. + +Note that after we close the file, its descriptor is returned to the free descriptor pool, and the next time a file (maybe another file) is opened, the same number comes into play again. + +For a neat shutdown, we will explicitly close all open files. + +``` +   for(int i = 0; i < ArraySize(ha); ++i) +   { +      if(ha[i] != INVALID_HANDLE) +      { +        FileClose(ha[i]); +      } +   } +} + +``` diff --git a/skills/mql5/references/book/03-common/0179-common-files-files-handles.md b/skills/mql5/references/book/03-common/0179-common-files-files-handles.md new file mode 100644 index 0000000..9d1e50c --- /dev/null +++ b/skills/mql5/references/book/03-common/0179-common-files-files-handles.md @@ -0,0 +1,276 @@ +# Managing file descriptors + +Since we need to constantly remember about open files and to release local descriptors on any exit from functions, it would be efficient to entrust the entire routine to special objects. + +This approach is well-known in programming and is called Resource Acquisition Is Initialization (RAII). Using RAII makes it easier to control resources and ensure they are in the correct state. In particular, this is especially effective if the function that opens the file (and creates an owner object for it) exits from several different places. + +The scope of RAII is not limited to files. In the section [Object type templates](/en/book/oop/templates/templates_objects), we created the AutoPtr class, which manages a pointer to an object. It was another example of this concept, since a pointer is also a resource (memory), and it is very easy to lose it as well as it is resource-consuming to release it in several different branches of the algorithm. + +A file wrapper class can be useful in another way as well. The file API does not provide a function that would allow you to get the name of a file by a descriptor (despite the fact that such a relationship certainly exists internally). At the same time, inside the object, we can store this name and implement our own binding to the descriptor. + +In the simplest case, we need some class that stores a file descriptor and automatically closes it in the destructor. An example implementation is shown in the FileHandle.mqh file. + +``` +class FileHandle +{ +   int handle; +public: +   FileHandle(const int h = INVALID_HANDLE) : handle(h) +   { +   } +    +   FileHandle(int &holder, const int h) : handle(h) +   { +      holder = h; +   } +    +   int operator=(const int h) +   { +      handle = h; +      return h; +   } +   ... + +``` + +Two constructors, as well as an overloaded assignment operator, ensure that an object is bound to a file (descriptor). The second constructor allows you to pass a reference to a local variable (from the calling code), which will additionally get a new descriptor. This will be a kind of external alias for the same descriptor, which can be used in the usual way in other function calls. + +But you can do without an alias too. For these cases, the class defines the operator '~', which returns the value of the internal handle variable. + +``` +   int operator~() const +   { +      return handle; +   } + +``` + +Finally, the most important thing for which the class was implemented is the smart destructor: + +``` +   ~FileHandle() +   { +      if(handle != INVALID_HANDLE) +      { +         ResetLastError(); +         // will set internal error code if handle is invalid +         FileGetInteger(handle, FILE_SIZE); +         if(_LastError == 0) +         { +            #ifdef FILE_DEBUG_PRINT +               Print(__FUNCTION__, ": Automatic close for handle: ", handle); +            #endif +            FileClose(handle); +         } +         else +         { +            PrintFormat("%s: handle %d is incorrect, %s(%d)",  +               __FUNCTION__, handle, E2S(_LastError), _LastError); +         } +      } +   } + +``` + +In it, after several checks, FileClose is called for the controlled handle variable. The point is that the file can be explicitly closed elsewhere in the program, although this is no longer required with this class. As a result, the descriptor may become invalid by the time the destructor is called when the execution of the algorithm leaves the block in which the FileHandle object is defined. To find this out, a dummy call to the [FileGetInteger](/en/book/common/files/files_properties) function is used. It is a dummy because it doesn't do anything useful. If the internal error code remains 0 after the call, the descriptor is valid. + +We can omit all these checks and simply write the following: + +``` +   ~FileHandle() +   { +      if(handle != INVALID_HANDLE) +      { +         FileClose(handle); +      } +   } + +``` + +If the descriptor is corrupted, FileClose won't return any warning. But we have added checks to be able to output diagnostic information. + +Let's try the FileHandle class in action. The test script for it is called FileHandle.mq5. + +``` +const string dummy = "MQL5Book/dummy"; +    +void OnStart() +{ +   // creating a new file or open an existing one and reset it +   FileHandle fh1(PRTF(FileOpen(dummy,  +      FILE_TXT | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ))); // 1 +   // another way to connect the descriptor via '=' +   int h = PRTF(FileOpen(dummy,  +      FILE_TXT | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ)); // 2 +   FileHandle fh2 = h; +   // and another supported syntax: +   // int f; +   // FileHandle ff(f, FileOpen(dummy, +   //    FILE_TXT | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ)); +    +   // data is supposed to be written here +   // ... +    +   // close the file manually (this is not necessary; only done to demonstrate  +   // that the FileHandle will detect this and won't try to close it again) +   FileClose(~fh1); // operator '~' applied to an object returns a handle +    +   // descriptor handle in variable 'h' bound to object 'fh2' is not manually closed +   // and will be automatically closed in the destructor +} + +``` + +According to the output in the log, everything works as planned: + +``` +   FileHandle::~FileHandle: Automatic close for handle: 2 +   FileHandle::~FileHandle: handle 1 is incorrect, INVALID_FILEHANDLE(5007) + +``` + +However, if there are lots of files, creating a tracking object copy for each of them can become an inconvenience. For such situations, it makes sense to design a single object that collects all descriptors in a given context (for example, inside a function). + +Such a class is implemented in the FileHolder.mqh file and is shown in the FileHolder.mq5 script. One copy of FileHolder itself creates upon request auxiliary observing objects of the FileOpener class, which shares common features with FileHandle, especially the destructor, as well as the handle field. + +To open a file via FileHolder, you should use its FileOpen method (its signature repeats the signature of the standard FileOpen function). + +``` +class FileHolder +{ +   static FileOpener *files[]; +   int expand() +   { +      return ArrayResize(files, ArraySize(files) + 1) - 1; +   } +public: +   int FileOpen(const string filename, const int flags,  +                const ushort delimiter = '\t', const uint codepage = CP_ACP) +   { +      const int n = expand(); +      if(n > -1) +      { +         files[n] = new FileOpener(filename, flags, delimiter, codepage); +         return files[n].handle; +      } +      return INVALID_HANDLE; +   } + +``` + +All FileOpener objects add up in the files array for tracking their lifetime. In the same place, zero elements mark the moments of registration of local contexts (blocks of code) in which FileHolder objects are created. The FileHolder constructor is responsible for this. + +``` +   FileHolder() +   { +      const int n = expand(); +      if(n > -1) +      { +         files[n] = NULL; +      } +   } + +``` + +As we know, during the execution of a program, it enters nested code blocks (it calls functions). If they require the management of local file descriptors, the FileHolder objects (one per block or less) should be described there. According to the rules of the stack (first in, last out), all such descriptions add up at files and then are released in reverse order as the program leaves the contexts. The destructor is called at each such moment. + +``` +   ~FileHolder() +   { +      for(int i = ArraySize(files) - 1; i >= 0; --i) +      { +         if(files[i] == NULL) +         { +            // decrement array and exit +            ArrayResize(files, i); +            return; +         } +          +         delete files[i]; +      } +   } + +``` + +Its task is to remove the last FileOpener objects in the array up to the first encountered zero element, which indicates the boundary of the context (further in the array are descriptors from another, external context). + +You can study the whole class on your own. + +Let's look at its use in the test script FileHolder.mq5. In addition to the OnStart function, it has SubFunc. Operations with files are performed in both contexts. + +``` +const string dummy = "MQL5Book/dummy"; +    +void SubFunc() +{ +   Print(__FUNCTION__, " enter"); +   FileHolder holder; +   int h = PRTF(holder.FileOpen(dummy,  +      FILE_BIN | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ)); +   int f = PRTF(holder.FileOpen(dummy,  +      FILE_BIN | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ)); +   // use h and f +   // ... +   // no need to manually close files and track early function exits +   Print(__FUNCTION__, " exit"); +} +  +void OnStart() +{ +   Print(__FUNCTION__, " enter"); +    +   FileHolder holder; +   int h = PRTF(holder.FileOpen(dummy,  +      FILE_BIN | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ)); +   // writing data and other actions on the file by descriptor +   // ... +   /* +   int a[] = {1, 2, 3}; +   FileWriteArray(h, a); +   */ +    +   SubFunc(); +   SubFunc(); +    + if(rand() >32000) // simulate branching by conditions +   { +      // thanks to the holder we don't need an explicit call +      // FileClose(h); +      Print(__FUNCTION__, " return"); +      return; // there can be many exits from the function +   } +    +   /* +     ... more code +   */ +    +   // thanks to the holder we don't need an explicit call +   // FileClose(h); +   Print(__FUNCTION__, " exit"); +} + +``` + +We have not closed any handles manually, instances of FileHolder will do it automatically in the destructors. + +Here is an example of logging output: + +``` +OnStart enter +holder.FileOpen(dummy,FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ)=1 / ok +SubFunc enter +holder.FileOpen(dummy,FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ)=2 / ok +holder.FileOpen(dummy,FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ)=3 / ok +SubFunc exit +FileOpener::~FileOpener: Automatic close for handle: 3 +FileOpener::~FileOpener: Automatic close for handle: 2 +SubFunc enter +holder.FileOpen(dummy,FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ)=2 / ok +holder.FileOpen(dummy,FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ)=3 / ok +SubFunc exit +FileOpener::~FileOpener: Automatic close for handle: 3 +FileOpener::~FileOpener: Automatic close for handle: 2 +OnStart exit +FileOpener::~FileOpener: Automatic close for handle: 1 + +``` diff --git a/skills/mql5/references/book/03-common/0180-common-files-files-txt-codepage.md b/skills/mql5/references/book/03-common/0180-common-files-files-txt-codepage.md new file mode 100644 index 0000000..6ade2ad --- /dev/null +++ b/skills/mql5/references/book/03-common/0180-common-files-files-txt-codepage.md @@ -0,0 +1,101 @@ +# Selecting an encoding for text mode + +For written text files, the encoding should be chosen based on the characteristics of the text or adjusted to the requirements of external programs for which the generated files are intended. If there are no external requirements, you can follow the rule to always use ANSI for plain texts with numbers, English letters and punctuation (a table of 128 such international characters is given in the section [String comparison](/en/book/common/strings/strings_comparison)). When working with various languages or special characters, use UTF-8 or Unicode, i.e. respectively: + +``` +int u8 = FileOpen("utf8.txt", FILE_WRITE | FILE_TXT | FILE_ANSI, 0, CP_UTF8); +int u0 = FileOpen("unicode.txt", FILE_WRITE | FILE_TXT | FILE_UNICODE); + +``` + +For example, these settings are useful for saving the names of financial instruments to a file, since they sometimes use special characters that denote currencies or trading modes. + +Reading your own files should not be a problem, because it is enough to specify the same encoding settings when reading as you did when writing. However, text files can come from different sources. Their encoding may be unknown, or subject to change without prior notice. Therefore, here comes the question of what to do if some of the files can be supplied as single-byte strings (ANSI), some as two-byte strings (Unicode), and some as UTF-8 encoding. + +Encoding can be selected via the [input parameters](/en/book/basis/variables/input_variables) of the program. However, this is effective only for one file, and if you have to open many different files, their encodings may not match. Therefore, it is desirable to instruct the system to make the correct model choice on the fly (from file to file). + +MQL5 does not allow 100% automatic detection and application of correct encodings, however, there is one most universal mode for reading a variety of text files. To do this, you need to set the following input parameters of the FileOpen function: + +``` +int h = FileOpen(filename, FILE_READ | FILE_TXT | FILE_ANSI, 0, CP_UTF8); + +``` + +There are several factors at work. + +First, the UTF-8 encoding transparently skips the mentioned 128 characters in any ANSI encoding (i.e. they are transmitted "one to one"). + +Second, it is the most popular for Internet protocols. + +Third, MQL5 has an additional built-in analysis for text formatting in two-byte Unicode, which allows you to automatically switch the file operation mode to FILE_UNICODE, if necessary, regardless of the specified parameters. The fact is that files in Unicode format are usually preceded by a special pair of identifiers: 0xFFFE, or vice versa, 0xFEFF. This sequence is called the Byte Order Mark (BOM). It is needed because, as we know, bytes can be stored inside numbers in a different order on different platforms (this was discussed in the section [Endianness control in integers](/en/book/common/maths/maths_byte_swap)). + +The FILE_UNICODE format uses a 2-byte integer (code) per character, so byte order becomes important, unlike other encodings. The Windows byte order BOM is 0xFFFE. If the MQL5 core finds this label at the beginning of a text file, its reading will automatically switch to Unicode mode. + +Let's see how the different mode settings work with text files of different encodings. For this, we will use the FileText.mq5 script and several text files with the same content, but in different encodings (the size in bytes is indicated in brackets): + +- ansi1252.txt (50): European encoding 1252 (it will be displayed in full without distortion in Windows with the European language) +- unicode1.txt (102): two-byte Unicode, at the beginning is the inherent Windows BOM 0xFFFE +- unicode2.txt (100): two-byte Unicode without BOM (in general, BOM is optional) +- unicode3.txt (102): two-byte Unicode, at the beginning there is BOM inherent to Unix, 0xFEFF +- utf8.txt (54): UTF-8 encoding + +In the OnStart function, we will read these files in loops with different settings of FileOpen. Please note that by using FileHandle (reviewed in the [previous section](/en/book/common/files/files_handles)) we don't have to worry about closing files: everything happens automatically within each iteration. + +``` +void OnStart() +{ +   Print("=====> UTF-8"); +   for(int i = 0; i < ArraySize(texts); ++i) +   { +      FileHandle fh(FileOpen(texts[i], FILE_READ | FILE_TXT | FILE_ANSI, 0, CP_UTF8)); +      Print(texts[i], " -> ", FileReadString(~fh)); +   } +    +   Print("=====> Unicode"); +   for(int i = 0; i < ArraySize(texts); ++i) +   { +      FileHandle fh(FileOpen(texts[i], FILE_READ | FILE_TXT | FILE_UNICODE)); +      Print(texts[i], " -> ", FileReadString(~fh)); +   } +    +   Print("=====> ANSI/1252"); +   for(int i = 0; i < ArraySize(texts); ++i) +   { +      FileHandle fh(FileOpen(texts[i], FILE_READ | FILE_TXT | FILE_ANSI, 0, 1252)); +      Print(texts[i], " -> ", FileReadString(~fh)); +   } +} + +``` + +The FileReadString function reads a string from a file. We'll cover it in the section on [writing and reading variables](/en/book/common/files/files_txt_atomic). + +Here is an example log with the script execution results: + +``` +=====> UTF-8 +MQL5Book/ansi1252.txt -> This is a text with special characters: ?? / ? / ? +MQL5Book/unicode1.txt -> This is a text with special characters: ±Σ / £ / ¥ +MQL5Book/unicode2.txt -> T +MQL5Book/unicode3.txt -> ?? +MQL5Book/utf8.txt -> This is a text with special characters: ±Σ / £ / ¥ +=====> Unicode +MQL5Book/ansi1252.txt -> 桔獩椠⁳⁡整瑸眠瑩⁨灳捥慩档牡捡整獲›㾱⼠ꌠ⼠ꔠ +MQL5Book/unicode1.txt -> This is a text with special characters: ±Σ / £ / ¥ +MQL5Book/unicode2.txt -> This is a text with special characters: ±Σ / £ / ¥ +MQL5Book/unicode3.txt -> 吀栀椀猀 椀猀 愀 琀攀砀琀 眀椀琀栀 猀瀀攀挀椀愀氀 挀栀愀爀愀挀琀攀爀猀㨀 넀 +MQL5Book/utf8.txt -> 桔獩椠⁳⁡整瑸眠瑩⁨灳捥慩档牡捡整獲›뇂ꏎ⼠술₣ ꗂ +=====> ANSI/1252 +MQL5Book/ansi1252.txt -> This is a text with special characters: ±? / £ / ¥ +MQL5Book/unicode1.txt -> This is a text with special characters: ±Σ / £ / ¥ +MQL5Book/unicode2.txt -> T +MQL5Book/unicode3.txt -> þÿ +MQL5Book/utf8.txt -> This is a text with special characters: Â±Î£ / Â£ / Â¥ + +``` + +The unicode1.txt file is always read correctly because it has BOM 0xFFFE, and the system ignores the settings in the source code. However, if the label is missing or is big-endian, this auto-detection does not work. Also, when setting FILE_UNICODE, we lose the ability to read single-byte texts and UTF-8. + +As a result, the aforementioned combination of FILE_ANSI and CP_UTF8 should be considered more resistant to variations in formatting. Selecting a specific national code page is only recommended when required explicitly. + +Despite the significant help provided for the programmer from the API when working with files in text mode, we can, if necessary, avoid the FILE_TXT or FILE_CSV mode, and open a text file in binary mode FILE_BINARY. This will shift all the complexity of parsing text and determining the encoding onto the shoulders of the programmer, but it will allow them to support other non-standard formats. But the main point here is that text can be read from and written to a file opened in binary mode. However, the opposite, in the general case, is impossible. A binary file with arbitrary data (which means, it does not contain strings exclusively) opened in text mode will most likely be interpreted as text "gibberish". If you need to write binary data to a text file, first use the [CryptEncode](/en/book/advanced/crypt/crypt_encode) function and CRYPT_BASE64 encoding. diff --git a/skills/mql5/references/book/03-common/0181-common-files-files-arrays.md b/skills/mql5/references/book/03-common/0181-common-files-files-arrays.md new file mode 100644 index 0000000..e3a5460 --- /dev/null +++ b/skills/mql5/references/book/03-common/0181-common-files-files-arrays.md @@ -0,0 +1,238 @@ +# Writing and reading arrays + +Two MQL5 functions are intended for writing and reading arrays: FileWriteArray and FileReadArray. With binary files, they allow you to handle arrays of any built-in type other than strings, as well as arrays of simple structures that do not contain string fields, objects, pointers, and dynamic arrays. These limitations are related to the optimization of the writing and reading processes, which is possible due to the exclusion of types with variable lengths. Strings, objects, and dynamic arrays are just like that. + +At the same time, when working with text files, these functions are able to operate on arrays of type string (other types of arrays in files with FILE_TXT/FILE_CSV mode are not allowed by these functions). Such arrays are stored in a file in the following format: one element per line. + +If you need to store structures or classes without type restrictions in a file, use type-specific functions that process one value per call. They are described in two sections on writing and reading variables of built-in types: for [binary](/en/book/common/files/files_bin_atomic) and [text](/en/book/common/files/files_txt_atomic) files. + +In addition, support for structures with strings can be organized through internal optimization of information storage. For example, instead of string fields, you can use integer fields, which will contain the indices of the corresponding strings in a separate array with strings. Given the possibility of redefining many operations (in particular, the assignment) using OOP tools and obtaining a structural element of an array by number, the appearance of the algorithm will practically not change. But when writing, you can first open a file in binary mode and call FileWriteArray for an array with a simplified structure type and then reopen the file in text mode and add an array of all strings to it using the second FileWriteArray call. To read such a file, you should provide a header at the beginning of it containing the number of elements in the arrays in order to pass it as the count parameter into FileReadArray (see further along). + +If you need to save or read not an array of structures, but a single structure, use the FileWriteStruct and FileReadStruct functions which are described in the [next section](/en/book/common/files/files_bin_structs). + +Let's study function signatures and then consider a general example (FileArray.mq5). + +uint FileWriteArray(int handle, const void &array[], int start = 0, int count = WHOLE_ARRAY) + +The function writes the array array to a file with the handle descriptor. The array can be multidimensional. The start and count parameters allow to set the range of elements; by default, it is equal to the entire array. In the case of multidimensional arrays, the start index and the number of elements count refer to continuous numbering across all dimensions, not the first dimension of the array. For example, if the array has the configuration [][5], then the start value equal to 7 will point to the element with indexes [1][2], and count = 2 will add the element [1][3] to it. + +The function returns the number of written elements. In case of an error, it will be 0. + +If handle is received in binary mode, arrays can be of any built-in type except strings, or simple structure types. If handle is opened in any of the text modes, the array must be of type string. + +uint FileReadArray(int handle, const void &array[], int start = 0, int count = WHOLE_ARRAY) + +The function reads data from a file with the handle descriptor into an array. The array can be multidimensional and dynamic. For multidimensional arrays, the start and count parameters work on the basis of the continuous numbering of elements in all dimensions, described above. A dynamic array, if necessary, automatically increases in size to fit the data being read. If start is greater than the original length of the array, these intermediate elements will contain random data after memory allocation (see the example). + +Pay attention that the function cannot control whether the configuration of the array used when writing the file matches the configuration of the receiving array when reading. Basically, there is no guarantee that the file being read was written with FileWriteArray. + +  + +To check the validity of the data structure, some predefined formats of initial headers or other descriptors inside files are usually used. The functions themselves will read any contents of the file within its size and place it in the specified array. + +If handle is received in binary mode, arrays can be any of the built-in non-string types or simple structure types. If handle is opened in text mode, the array must be of type string. + +Let's check the work both in binary and in text mode using the FileArray.mq5 script. To do this, we will reserve two file names. + +``` +const string raw = "MQL5Book/array.raw"; +const string txt = "MQL5Book/array.txt"; + +``` + +Three arrays of type long and two arrays of type string are described in the OnStart function. Only the first array of each type is filled with data, and all the rest will be checked for reading after the files are written. + +``` +void OnStart() +{ +   long numbers1[][2] = {{1, 4}, {2, 5}, {3, 6}}; +   long numbers2[][2]; +   long numbers3[][2]; +    +   string text1[][2] = {{"1.0", "abc"}, {"2.0", "def"}, {"3.0", "ghi"}}; +   string text2[][2]; +   ... + +``` + +In addition, to test operations with structures, the following 3 types are defined: + +``` +struct TT +{ +   string s1; +   string s2; +}; +   +struct B +{ +private: +   int b; +public: +   void setB(const int v) { b = v; } +}; +   +struct XYZ : public B +{ +   color x, y, z; +}; + +``` + +We will not be able to use a structure of the TT type in the described functions because it contains string fields. It is needed to demonstrate a potential compilation error in a commented statement (see further along). Inheritance between structures B and XYZ, as well as the presence of a closed field, are not an obstacle for the functions FileWriteArray and FileReadArray. + +The structures are used to declare a pair of arrays: + +``` + TTtt[]; // empty, because data is not important +   XYZ xyz[1]; +   xyz[0].setB(-1); +   xyz[0].x = xyz[0].y = xyz[0].z = clrRed; + +``` + +Let's start with binary mode. Let's create a new file or open an existing file, dumping its contents. Then, in three FileWriteArray calls, we will try to write three arrays: numbers1, text1 and xyz. + +``` +   int writer = PRTF(FileOpen(raw, FILE_BIN | FILE_WRITE)); // 1 / ok +   PRTF(FileWriteArray(writer, numbers1)); // 6 / ok +   PRTF(FileWriteArray(writer, text1)); // 0 / FILE_NOTTXT(5012) +   PRTF(FileWriteArray(writer, xyz)); // 1 / ok +   FileClose(writer); +   ArrayPrint(numbers1); + +``` + +Arrays numbers1 and xyz are written successfully, as indicated by the number of items written. The text1 array fails with a FILE_NOTTXT(5012) error because string arrays require the file to be opened in text mode. Therefore the content xyz will be located in the file immediately after all elements of numbers1. + +Note that each write (or read) function starts writing (or reading) data to the current position within the file, and shifts it by the size of the written or read data. If this pointer is at the end of the file before the write operation, the file size is increased. If the end of the file is reached while reading, the pointer no longer moves and the system raises a special internal error code 5027 (FILE_ENDOFFILE). In a new file of the zero size, the beginning and end are the same. + +From an array text1, 0 items were written, so nothing in the file reminds you that between two successful calls FileWriteArray there was one failure. + +In the test script, we simply output the result of the function and the status (error code) to the log, but in a real program, we should analyze problems on the go and take some actions: fix something in the parameters, in the file settings, or interrupt the process with a message to the user. + +Let's read a file into the numbers2 array. + +``` +   int reader = PRTF(FileOpen(raw, FILE_BIN | FILE_READ)); // 1 / ok +   PRTF(FileReadArray(reader, numbers2)); // 8 / ok +   ArrayPrint(numbers2); + +``` + +Since two different arrays were written to the file (not only numbers1, but also xyz), 8 elements were read into the receiving array (i.e., the entire file to the end, because otherwise was not specified using parameters). + +Indeed, the size of the structure XYZ is 16 bytes (4 fields of 4 bytes: one int and three color), which corresponds to one row in the array numbers2 (2 elements of type long). In this case, it's a coincidence. As noted above, the functions have no idea about the configuration and size of the raw data and can read anything into any array: the programmer must monitor the validity of the operation. + +Let's compare the initial and received states. Source array numbers1: + +``` +       [,0][,1] +   [0,]   1   4 +   [1,]   2   5 +   [2,]   3   6 + +``` + +Resulting array numbers2: + +``` +                 [,0]          [,1] +   [0,]             1             4 +   [1,]             2             5 +   [2,]             3             6 +   [3,] 1099511627775 1095216660735 + +``` + +The beginning of the numbers2 array completely matches the original numbers1 array, i.e., writing and reading through the file work properly. + +The last row is entirely occupied by a single structure XYZ (with correct values, but incorrect representation as two numbers of type long). + +Now we get to the file beginning (using the FileSeek function, which we will discuss later in the section [Position control within a file](/en/book/common/files/files_cursor)) and call FileReadArray indicating the number and quantity of elements, i.e., we perform a partial reading. + +``` +   PRTF(FileSeek(reader, 0, SEEK_SET)); // true +   PRTF(FileReadArray(reader, numbers3, 10, 3)); +   FileClose(reader); +   ArrayPrint(numbers3); + +``` + +Three elements are read from the file and placed, starting at index 10, into the receiving array numbers3. Since the file is read from the beginning, these elements are the values 1, 4, 2. And since a two-dimensional array has the configuration [][2], the through index 10 points to the element [5,0]. Here's what it looks like in memory: + +``` +       [,0][,1] +   [0,]   1   4 +   [1,]   1   4 +   [2,]   2   6 +   [3,]   0   0 +   [4,]   0   0 +   [5,]   1   4 +   [6,]   2   0 + +``` + +Items marked in yellow are random (may change for different script runs). It is possible that they will all be zero, but this is not guaranteed. The numbers3 array initially was empty and the FileReadArray call initiated an allocation of memory required to receive 3 elements at offset 10 (total 13). The selected block is not filled with anything, and only 3 numbers are read from the file. Therefore, elements with through indices from 0 to 9 (i.e. the first 5 rows), as well as the last one, with index 13, contain garbage. + +Multidimensional arrays are scaled along the first dimension, and therefore an increase of 1 number means adding the entire configuration along higher dimensions. In this case, the distribution concerns a series of two numbers ([][2]). In other words, the requested size 13 is rounded up to a multiple of two, that is, 14. + +Finally, let's test how the functions work with string arrays. Let's create a new file or open an existing file, dumping its contents. Then, in two FileWriteArray calls, we will write the text1 and numbers1 arrays. + +``` +   writer = PRTF(FileOpen(txt, FILE_TXT | FILE_ANSI | FILE_WRITE)); // 1 / ok +   PRTF(FileWriteArray(writer, text1)); // 6 / ok +   PRTF(FileWriteArray(writer, numbers1)); // 0 / FILE_NOTBIN(5011) +   FileClose(writer); + +``` + +The string array is saved successfully. The numeric array is ignored with a FILE_NOTBIN(5011) error because it must open the file in binary mode. + +When trying to write an array of structures tt, we get a compilation error with a lengthy message "structures or classes with objects are not allowed". What the compiler actually means is that it doesn't like fields like string (it is assumed that strings and dynamic arrays have an internal representation of some service objects). Thus, despite the fact that the file is opened in text mode and there are only text fields in the structure, this combination is not supported in MQL5. + +``` +   // COMPILATION ERROR: structures or classes containing objects are not allowed +   FileWriteArray(writer, tt); + +``` + +The presence of string fields makes the structure "complicated" and unsuitable for working with functions FileWriteArray/FileReadArray in any mode. + +After running the script, you can change to the directory MQL5/Files/MQL5Book and examine the contents of the generated files. + +Earlier, in the section [Writing and reading files in simplified mode](/en/book/common/files/files_save_load), we discussed the FileSave and FileLoad functions. In the test script (FileSaveLoad.mq5), we have implemented the equivalent versions of these functions using FileWriteArray and FileReadArray. But we have not seen them in detail. Since we are now familiar with these new functions, we can examine the source code: + +``` +template +bool MyFileSave(const string name, const T &array[], const int flags = 0) +{ +   const int h = FileOpen(name, FILE_BIN | FILE_WRITE | flags); +   if(h == INVALID_HANDLE) return false; +   FileWriteArray(h, array); +   FileClose(h); +   return true; +} +    +template +long MyFileLoad(const string name, T &array[], const int flags = 0) +{ +   const int h = FileOpen(name, FILE_BIN | FILE_READ | flags); +   if(h == INVALID_HANDLE) return -1; +   const uint n = FileReadArray(h, array, 0, (int)(FileSize(h) / sizeof(T))); +   // this version has the following check added compared to the standard FileLoad: +   // if the file size is not a multiple of the structure size, print a warning +   const ulong leftover = FileSize(h) - FileTell(h); +   if(leftover != 0) +   { +      PrintFormat("Warning from %s: Some data left unread: %d bytes",  +         __FUNCTION__, leftover); +      SetUserError((ushort)leftover); +   } +   FileClose(h); +   return n; +} + +``` + +MyFileSave is built on a single call of FileWriteArray, and MyFileLoad on FileReadArray call, between a pair of FileOpen/FileClose calls. In both cases, all available data is written and read. Thanks to templates, our functions are also able to accept arrays of arbitrary types. But if any unsupported type (for example, a class) is deduced as a meta parameter T, then a compilation error will occur, as is the case with incorrect access to built-in functions. diff --git a/skills/mql5/references/book/03-common/0182-common-files-files-bin-structs.md b/skills/mql5/references/book/03-common/0182-common-files-files-bin-structs.md new file mode 100644 index 0000000..eea500b --- /dev/null +++ b/skills/mql5/references/book/03-common/0182-common-files-files-bin-structs.md @@ -0,0 +1,168 @@ +# Writing and reading structures (binary files) + +In the previous section, we learned how to perform I/O operations on arrays of structures. When reading or writing is related to a separate structure, it is more convenient to use the pair of functions FileWriteStruct and FileReadStruct. + +uint FileWriteStruct(int handle, const void &data, int size = -1) + +The function writes the contents of a simple data structure to a binary file with the handle descriptor. As we know, such structures can only contain fields of built-in non-string types and nested simple structures. + +The main feature of the function is the size parameter. It helps to set the number of bytes to be written, which allows us to discard some part of the structure (its end). By default, the parameter is -1, which means that the entire structure is saved. If size is greater than the size of the structure, the excess is ignored, i.e., only the structure is written, sizeof(data) bytes. + +On success, the function returns the number of bytes written, on error it returns 0. + +uint FileReadStruct(int handle, void &data, int size = -1) + +The function reads content from a binary file with the handle descriptor to the data structure. The size parameter specifies the number of bytes to be read. If it is not specified or exceeds the size of the structure, then the exact size of the specified structure is used. + +On success, the function returns the number of bytes read, on error it returns 0. + +The option to cut off the end of the structure is present only in the FileWriteStruct and FileReadStruct functions. Therefore, their use in a loop becomes the most suitable alternative for saving and reading an array of trimmed structures: the FileWriteArray and FileReadArray functions do not have this capability, and writing and reading by individual fields can be more resource-intensive (we will look at the corresponding functions in the following sections). + +It should be noted that in order to use this feature, you should design your structures in such a way that all temporary and intermediary calculation fields that should not be saved are located at the end of the structure. + +Let's look at examples of using these two functions in the script FileStruct.mq5. + +Suppose we want to archive the latest quotes from time to time, in order to be able to check their invariance in the future or to compare with similar periods from other providers. Basically, this can be done manually through the Symbols dialog (in the Bars tab) in MetaTrader 5. But this would require extra effort and adherence to a schedule. It is much easier to do this automatically, from the program. In addition, manual export of quotes is done in CSV text format, and we may need to send files to an external server. Therefore, it is desirable to save them in a compact binary form. In addition to this, let's assume that we are not interested in information about ticks, spread and real volumes (which are always empty for Forex symbols). + +In the section [Comparing, sorting, and searching in arrays](/en/book/common/arrays/arrays_compare_sort_search), we considered the MqlRates structure and the CopyRates function. They will be described in detail [later](/en/book/applications/timeseries/timeseries_mqlrates), while now we will use them once more as a testing ground for file operations. + +Using the size parameter in FileWriteStruct, we can save only part of the MqlRates structure, without the last fields. + +At the beginning of the script, we define the macros and the name of the test file. + +``` +#define BARLIMIT 10 // number of bars to write +#define HEADSIZE 10 // size of the header of our format  +const string filename = "MQL5Book/struct.raw"; + +``` + +Of particular interest is the HEADSIZE constant. As mentioned earlier, file functions as such are not responsible for the consistency of the data in the file, and the types of structures into which this data is read. The programmer must provide such control in their code. Therefore, a certain header is usually written at the beginning of the file, with the help of which you can, firstly, make sure that this is a file of the required format, and secondly, save the meta-information in it that is necessary for proper reading. + +In particular, the title may indicate the number of entries. Strictly speaking, the latter is not always necessary, because we can read the file gradually until it ends. However, it is more efficient to allocate memory for all expected records at once, based on the counter in the header. + +For our purposes, we have developed a simple structure FileHeader. + +``` +struct FileHeader +{ +   uchar signature[HEADSIZE]; +   int n; +   FileHeader(const int size = 0) : n(size) +   { +      static uchar s[HEADSIZE] = {'C','A','N','D','L','E','S','1','.','0'}; +      ArrayCopy(signature, s); +   } +}; + +``` + +It starts with the text signature "CANDLES" (in the signature field), the version number "1.0" (same location), and the number of entries (the n field). Since we cannot use a string field for the signature (then the structure would no longer be simple and meet the requirements of file functions), the text is actually packed into the uchar array of the fixed size HEADSIZE. Its initialization in the instance is done by the constructor based on the local static copy. + +In the OnStart function, we request the BARLIMIT of the last bars, open the file in FILE_WRITE mode, and write the header followed by the resulting quotes in a truncated form to the file. + +``` +void OnStart() +{ +   MqlRates rates[], candles[]; +   int n = PRTF(CopyRates(_Symbol, _Period, 0, BARLIMIT, rates)); // 10 / ok +   if(n < 1) return; +   +   // create a new file or overwrite the old one from scratch +   int handle = PRTF(FileOpen(filename, FILE_BIN | FILE_WRITE)); // 1 / ok +   + FileHeaderfh(n);// header with the actual number of entries +   +   // first write the header +   PRTF(FileWriteStruct(handle, fh)); // 14 / ok +   +   // then write the data +   for(int i = 0; i < n; ++i) +   { +      FileWriteStruct(handle, rates[i], offsetof(MqlRates, tick_volume)); +   } +   FileClose(handle); +   ArrayPrint(rates); +   ... + +``` + +As the size parameter value in the FileWriteStruct function, we use an expression with a familiar operator [offsetof](/en/book/oop/structs_and_unions/structs_pack_dll): offsetof(MqlRates, tick_volume), i.e., all fields starting with tick_volume are discarded when writing to the file. + +To test the data reading, let's open the same file in FILE_READ mode and read the FileHeader structure. + +``` +   handle = PRTF(FileOpen(filename, FILE_BIN | FILE_READ)); // 1 / ok +   FileHeader reference, reader; +   PRTF(FileReadStruct(handle, reader)); // 14 / ok +   // if the headers don't match, it's not our data +   if(ArrayCompare(reader.signature, reference.signature)) +   { +      Print("Wrong file format; 'CANDLES' header is missing"); +      return; +   } + +``` + +The reference structure contains the unchanged default header (signature). The reader structure got 14 bytes from the file. If the two signatures match, we can continue to work, since the file format turned out to be correct, and the reader.n field contains the number of entries read from the file. We allocate and zero out the required size memory for the receiving array candles, and then read all entries into it. + +``` +   PrintFormat("Reading %d candles...", reader.n); + ArrayResize(candles, reader.n);// allocate memory for the expected data in advance +   ZeroMemory(candles); +    +   for(int i = 0; i < reader.n; ++i) +   { +      FileReadStruct(handle, candles[i], offsetof(MqlRates, tick_volume)); +   } +   FileClose(handle); +   ArrayPrint(candles); +} + +``` + +Zeroing was required because the MqlRates structures are read partially, and the remaining fields would contain garbage without zeroing. + +Here is the log showing the initial data (as a whole) for XAUUSD,H1. + +``` +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.08.16 03:00:00 1778.86 1780.58 1778.12 1780.56          3049        5             0 +[1] 2021.08.16 04:00:00 1780.61 1782.58 1777.10 1777.13          4633        5             0 +[2] 2021.08.16 05:00:00 1777.13 1780.25 1776.99 1779.21          3592        5             0 +[3] 2021.08.16 06:00:00 1779.26 1779.26 1776.67 1776.79          2535        5             0 +[4] 2021.08.16 07:00:00 1776.79 1777.59 1775.50 1777.05          2052        6             0 +[5] 2021.08.16 08:00:00 1777.03 1777.19 1772.93 1774.35          3213        5             0 +[6] 2021.08.16 09:00:00 1774.38 1775.41 1771.84 1773.33          4527        5             0 +[7] 2021.08.16 10:00:00 1773.26 1777.42 1772.84 1774.57          4514        5             0 +[8] 2021.08.16 11:00:00 1774.61 1776.67 1773.69 1775.95          3500        5             0 +[9] 2021.08.16 12:00:00 1775.96 1776.12 1773.68 1774.44          2425        5             0 + +``` + +Now let's see what was read. + +``` +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.08.16 03:00:00 1778.86 1780.58 1778.12 1780.56             0        0             0 +[1] 2021.08.16 04:00:00 1780.61 1782.58 1777.10 1777.13             0        0             0 +[2] 2021.08.16 05:00:00 1777.13 1780.25 1776.99 1779.21             0        0             0 +[3] 2021.08.16 06:00:00 1779.26 1779.26 1776.67 1776.79             0        0             0 +[4] 2021.08.16 07:00:00 1776.79 1777.59 1775.50 1777.05             0        0             0 +[5] 2021.08.16 08:00:00 1777.03 1777.19 1772.93 1774.35             0        0             0 +[6] 2021.08.16 09:00:00 1774.38 1775.41 1771.84 1773.33             0        0             0 +[7] 2021.08.16 10:00:00 1773.26 1777.42 1772.84 1774.57             0        0             0 +[8] 2021.08.16 11:00:00 1774.61 1776.67 1773.69 1775.95             0        0             0 +[9] 2021.08.16 12:00:00 1775.96 1776.12 1773.68 1774.44             0        0             0 + +``` + +The quotes match, but the last three fields in each structure are empty. + +You can open the MQL5/Files/MQL5Book folder and examine the internal representation of the struct.raw file (use a viewer that supports binary mode; an example is shown below). + +![Options for presenting a binary file with quotes archive in an external viewer](pics/structraw.png) + +Options for presenting a binary file with quotes archive in an external viewer + +Here is a typical way to display binary files: the left column shows addresses (offsets from the beginning of the file), byte codes are in the middle column, and the symbolic representations of the corresponding bytes are shown in the right column. The first and second columns use the hexadecimal notation for numbers. The characters in the right column may differ depending on the selected ANSI code page. It makes sense to pay attention to them only in those fragments where the presence of text is known. In our case, the signature "CANDLES1.0" is clearly "manifested" at the very beginning. Numbers should be analyzed by the middle column. In this column for example, after the signature, you can see the 4-byte value 0x0A000000, i.e., 0x0000000A in an inverted form (remember the section [Endianness control in integers](/en/book/common/maths/maths_byte_swap)): this is 10, the number of structures written. diff --git a/skills/mql5/references/book/03-common/0183-common-files-files-bin-atomic.md b/skills/mql5/references/book/03-common/0183-common-files-files-bin-atomic.md new file mode 100644 index 0000000..6619325 --- /dev/null +++ b/skills/mql5/references/book/03-common/0183-common-files-files-bin-atomic.md @@ -0,0 +1,328 @@ +# Writing and reading variables (binaries) + +If a structure contains fields of types that are prohibited for simple structures (strings, dynamic arrays, pointers), then it will not be possible to write it to a file or read from a file using the functions considered earlier. The same goes for class objects. However, such entities usually contain most of the data in programs and also require saving and restoring their state. + +Using the example of the header structure in the previous section, it was clearly shown that strings (and other types of variable length) can be avoided, but in this case, one has to invent alternative, more cumbersome implementations of algorithms (for example, replacing a string with an array of characters). + +To write and read data of arbitrary complexity, MQL5 provides sets of lower-level functions which operate on a single value of a particular type: double, float, int/uint, long/ulong, or string. All other built-in MQL5 types are equivalent to integers of different sizes: char/uchar is 1 byte, short/ushort is 2 bytes, color is 4 bytes, enumerations are 4 bytes, and datetime is 8 bytes. Such functions can be called atomic (i.e., indivisible), because the functions for reading and writing to files at the bit level no longer exist. + +Of course, element-by-element writing or reading also removes the restriction on file operations with dynamic arrays. + +As for pointers to objects, in the spirit of the OOP paradigm, we can allow them to save and restore objects: it is enough to implement in each class an interface (a set of methods) that is responsible for transferring important content to files and back, and using low-level functions. Then, if we come across a pointer field to another object as part of the object, we simply delegate saving or reading to it, and in turn, it will deal with its fields, among which there may be other pointers, and the delegation will continue deeper until will cover all elements. + +Please note that in this section we will look at atomic functions for binary files. Their counterparts for text files will be presented in the [next section](/en/book/common/files/files_txt_atomic). All functions in this section return the number of bytes written, or 0 in case of an error. + +uint FileWriteDouble(int handle, double value) + +uint FileWriteFloat(int handle, float value) + +uint FileWriteLong(int handle, long value) + +The functions write the value of the corresponding type passed in the parameter value (double, float, long) to a binary file with the handle descriptor. + +uint FileWriteInteger(int handle, int value, int size = INT_VALUE) + +The function writes the value integer to a binary file with the handle descriptor. The size of the value in bytes is set by the size parameter and can be one of the predefined constants: CHAR_VALUE (1), SHORT_VALUE (2), INT_VALUE (4, default), which corresponds to types char, short and int (signed and unsigned). + +The function supports an undocumented writing mode of a 3-byte integer. Its use is not recommended. + +The file pointer moves by the number of bytes written (not by the int size). + +uint FileWriteString(int handle, const string value, int length = -1) + +The function writes a string from the value parameter to a binary file with the handle descriptor. You can specify the number of characters to write the length parameter. If it is less than the length of the string, only the specified part of the string will be included in the file. If length is -1 or is not specified, the entire string is transferred to the file without the terminal null. If length is greater than the length of the string, extra characters are filled with zeros. + +Note that when writing to a file opened with the FILE_UNICODE flag (or without the FILE_ANSI flag), the string is saved in the Unicode format (each character takes up 2 bytes). When writing to a file opened with the FILE_ANSI flag, each character occupies 1 byte (foreign language characters may be distorted). + +The FileWriteString function can also work with text files. This aspect of its application is described in the next section. + +double FileReadDouble(int handle) + +float FileReadFloat(int handle) + +long FileReadLong(int handle) + +The functions read a number of the appropriate type, double, float or long, from a binary file with the specified descriptor. If necessary, convert the result to ulong (if an unsigned long is expected in the file at that position). + +int FileReadInteger(int handle, int size = INT_VALUE) + +The function reads an integer value from a binary file with the handle descriptor. The value size in bytes is specified in the size parameter. + +Since the result of the function is of type int, it must be explicitly converted to the required target type if it is different from int (i.e. to uint, or short/ushort, or char/uchar). Otherwise, you will at least get a compiler warning and at most a loss of sign. + +The fact is that when reading CHAR_VALUE or SHORT_VALUE, the default result is always positive (i.e. corresponds to uchar and ushort, which are wholly "fit" in int). In these cases, if the numbers are actually of types uchar and ushort, the compiler warnings are purely nominal, since we are already sure that inside the value of type int only 1 or 2 low bytes are filled, and they are unsigned. This happens without distortion. + +However, when storing signed values (types char and short) in the file, conversion becomes necessary because, without it, negative values will turn into inverse positive ones with the same bit representation (see the 'Signed and unsigned integers' part in the [Arithmetic type conversions](/en/book/basis/conversion/conversion_arithmetic) section). + +In any case, it is better to avoid warnings by explicit type conversion. + +The function supports 3-byte integer reading mode. Its use is not recommended. + +The file pointer moves by the number of bytes read (not by the size int). + +string FileReadString(int handle, int size = -1) + +The function reads a string of the specified size in characters from a file with the handle descriptor. The size parameter must be set when working with a binary file (the default value is only suitable for text files that use separator characters). Otherwise, the string is not read (the function returns an empty string), and the internal error code _LastError is 5016 (FILE_BINSTRINGSIZE). + +Thus, even at the stage of writing a string to a binary file, you need to think about how the string will be read. There are three main options: + +- Write strings with a null terminal character at the end. In this case, they will have to be analyzed character by character in a loop and combine characters into a string until 0 is encountered. +- Always write a string of the fixed (predefined) length. The length should be chosen with a margin for most scenarios, or according to the specification (terms of reference, protocol, etc.), but this is uneconomical and does not give a 100% guarantee that some rare string will not be shortened when writing to a file. +- Write the length as an integer before the string. + +The FileReadString function can also work with text files. This aspect of its application is described in the next section. + +Also note that if the size parameter is 0 (which can happen during some calculations), then the function does not read: the file pointer remains in the same place and the function returns an empty string. + +As an example for this section, we will improve the FileStruct.mq5 script from the previous section. The new program name is FileAtomic.mq5. + +The task remains the same: save a given number of truncated [MqlRates](/en/book/applications/timeseries/timeseries_mqlrates) structures with quotes to a binary file. But now the FileHeader structure will become a class (and the format signature will be stored in a string, not in an array of characters). A header of this type and an array of quotes will be part of another control class Candles, and both classes will be inherited from the Persistent interface for writing arbitrary objects to a file and reading from a file. + +Here is the interface: + +``` +interface Persistent +{ +   bool write(int handle); +   bool read(int handle); +}; + +``` + +In the FileHeader class, we will implement the saving and checking of the format signature (let's change it to "CANDLES/1.1") and of the names of the current symbol and chart timeframe (more about [_Symbol](/en/book/applications/charts/charts_main_properties) and [_Period](/en/book/applications/charts/charts_main_properties)). + +Writing is done in the implementation of the write method inherited from the interface. + +``` +class FileHeader : public Persistent +{ +   const string signature; +public: +   FileHeader() : signature("CANDLES/1.1") { } +   bool write(int handle) override +   { +      PRTF(FileWriteString(handle, signature, StringLen(signature))); +      PRTF(FileWriteInteger(handle, StringLen(_Symbol), CHAR_VALUE)); +      PRTF(FileWriteString(handle, _Symbol)); +      PRTF(FileWriteString(handle, PeriodToString(), 3)); +      return true; +   } + +``` + +The signature is written exactly according to its length since the sample is stored in the object and the same length will be set when reading. + +For the instrument of the current chart, we first save the length of its name in the file (1 byte is enough for lengths up to 255), and only then we save the string itself. + +The name of the timeframe never exceeds 3 symbols, if the constant prefix "PERIOD_" is excluded from it, therefore a fixed length is chosen for this string. The timeframe name without a prefix is obtained in the auxiliary function PeriodToString: it is in a separate header file Periods.mqh (it will be discussed in more detail in the section [Symbols and timeframes](/en/book/applications/timeseries/timeseries_symbol_period)). + +Reading is performed in read method in the reverse order (of course, it is assumed that the reading will be performed in a different, new object). + +``` +   bool read(int handle) override +   { +      const string sig = PRTF(FileReadString(handle, StringLen(signature))); +      if(sig != signature) +      { +         PrintFormat("Wrong file format, header is missing: want=%s vs got %s",  +            signature, sig); +         return false; +      } +      const int len = PRTF(FileReadInteger(handle, CHAR_VALUE)); +      const string sym = PRTF(FileReadString(handle, len)); +      if(_Symbol != sym) +      { +         PrintFormat("Wrong symbol: file=%s vs chart=%s", sym, _Symbol); +         return false; +      } +      const string stf = PRTF(FileReadString(handle, 3)); +      if(_Period != StringToPeriod(stf)) +      { +         PrintFormat("Wrong timeframe: file=%s(%s) vs chart=%s",  +            stf, EnumToString(StringToPeriod(stf)), EnumToString(_Period)); +         return false; +      } +      return true; +   } + +``` + +If any of the properties (signature, symbol, timeframe) does not match in the file and on the current chart, the function returns false to indicate an error. + +The reverse transformation of the timeframe name into the ENUM_TIMEFRAMES enumeration is done by the function StringToPeriod, also from the file Periods.mqh. + +The main Candles class for requesting, saving and reading the archive of quotes is as follows. + +``` +class Candles : public Persistent +{ +   FileHeader header; +   int limit; +   MqlRates rates[]; +public: +   Candles(const int size = 0) : limit(size) +   { +      if(size == 0) return; +      int n = PRTF(CopyRates(_Symbol, _Period, 0, limit, rates)); +      if(n < 1) +      { + limit =0; // initialization failed +      } + limit =n; // may be less than requested +   } + +``` + +The fields are the header of the FileHeader type, the requested number of bars limit, and an array receiving MqlRates structures from MetaTrader 5. The array is filled in the constructor. In case of an error, the limit field is reset to zero. + +Being derived from the Persistent interface, the Candles class requires the implementation of methods write and read. In the write method, we first instruct the header object to save itself, and then append the number of quotes, the date range (for reference), and the array itself to the file. + +``` +   bool write(int handle) override +   { +      if(!limit) return false; // no data +      if(!header.write(handle)) return false; +      PRTF(FileWriteInteger(handle, limit)); +      PRTF(FileWriteLong(handle, rates[0].time)); +      PRTF(FileWriteLong(handle, rates[limit - 1].time)); +      for(int i = 0; i < limit; ++i) +      { +         FileWriteStruct(handle, rates[i], offsetof(MqlRates, tick_volume)); +      } +      return true; +   } + +``` + +Reading is done in reverse order: + +``` +   bool read(int handle) override +   { +      if(!header.read(handle)) +      { +         return false; +      } +      limit = PRTF(FileReadInteger(handle)); +      ArrayResize(rates, limit); +      ZeroMemory(rates); +      // dates need to be read: they are not used, but this shifts the position in the file; +      // it was possible to explicitly change the position, but this function has not yet been studied +      datetime dt0 = (datetime)PRTF(FileReadLong(handle)); +      datetime dt1 = (datetime)PRTF(FileReadLong(handle)); +      for(int i = 0; i < limit; ++i) +      { +         FileReadStruct(handle, rates[i], offsetof(MqlRates, tick_volume)); +      } +      return true; +   } + +``` + +In a real program for archiving quotes, the presence of a range of dates would allow building their correct sequence over a long history by the file headers and, to some extent, would protect against arbitrary renaming of files. + +There is a simple print method to control the process: + +``` +   void print() const +   { +      ArrayPrint(rates); +   } + +``` + +In the main function of the script, we create two Candles objects, and using one of them, we first save the quotes archive and then restore it with the help of the other. Files are managed by the wrapper FileHandle that we already know (see section [File descriptor management](/en/book/common/files/files_handles)). + +``` +const string filename = "MQL5Book/atomic.raw"; +   +void OnStart() +{ +   // create a new file and reset the old one +   FileHandle handle(PRTF(FileOpen(filename,  +      FILE_BIN | FILE_WRITE | FILE_ANSI | FILE_SHARE_READ))); +   // form data +   Candles output(BARLIMIT); +   // write them to a file +   if(!output.write(~handle)) +   { +      Print("Can't write file"); +      return; +   } +   output.print(); +   +   // open the newly created file for checking +   handle = PRTF(FileOpen(filename,  +      FILE_BIN | FILE_READ | FILE_ANSI | FILE_SHARE_READ | FILE_SHARE_WRITE)); +   // create an empty object to receive quotes +   Candles inputs; +   // read data from the file into it +   if(!inputs.read(~handle)) +   { +      Print("Can't read file"); +   } +   else +   { +      inputs.print(); +   } + +``` + +Here is an example of logs of initial data for XAUUSD,H1: + +``` +FileOpen(filename,FILE_BIN|FILE_WRITE|FILE_ANSI|FILE_SHARE_READ)=1 / ok +CopyRates(_Symbol,_Period,0,limit,rates)=10 / ok +FileWriteString(handle,signature,StringLen(signature))=11 / ok +FileWriteInteger(handle,StringLen(_Symbol),CHAR_VALUE)=1 / ok +FileWriteString(handle,_Symbol)=6 / ok +FileWriteString(handle,PeriodToString(),3)=3 / ok +FileWriteInteger(handle,limit)=4 / ok +FileWriteLong(handle,rates[0].time)=8 / ok +FileWriteLong(handle,rates[limit-1].time)=8 / ok +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.08.17 15:00:00 1791.40 1794.57 1788.04 1789.46          8157        5             0 +[1] 2021.08.17 16:00:00 1789.46 1792.99 1786.69 1789.69          9285        5             0 +[2] 2021.08.17 17:00:00 1789.76 1790.45 1780.95 1783.30          8165        5             0 +[3] 2021.08.17 18:00:00 1783.30 1783.98 1780.53 1782.73          5114        5             0 +[4] 2021.08.17 19:00:00 1782.69 1784.16 1782.09 1782.49          3586        6             0 +[5] 2021.08.17 20:00:00 1782.49 1786.23 1782.17 1784.23          3515        5             0 +[6] 2021.08.17 21:00:00 1784.20 1784.85 1782.73 1783.12          2627        6             0 +[7] 2021.08.17 22:00:00 1783.10 1785.52 1782.37 1785.16          2114        5             0 +[8] 2021.08.17 23:00:00 1785.11 1785.84 1784.71 1785.80           922        5             0 +[9] 2021.08.18 01:00:00 1786.30 1786.34 1786.18 1786.20            13        5             0 + +``` + +And here is an example of the recovered data (recall that the structures are saved in a truncated form according to our hypothetical technical task): + +``` +FileOpen(filename,FILE_BIN|FILE_READ|FILE_ANSI|FILE_SHARE_READ|FILE_SHARE_WRITE)=2 / ok +FileReadString(handle,StringLen(signature))=CANDLES/1.1 / ok +FileReadInteger(handle,CHAR_VALUE)=6 / ok +FileReadString(handle,len)=XAUUSD / ok +FileReadString(handle,3)=H1 / ok +FileReadInteger(handle)=10 / ok +FileReadLong(handle)=1629212400 / ok +FileReadLong(handle)=1629248400 / ok +                 [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume] +[0] 2021.08.17 15:00:00 1791.40 1794.57 1788.04 1789.46             0        0             0 +[1] 2021.08.17 16:00:00 1789.46 1792.99 1786.69 1789.69             0        0             0 +[2] 2021.08.17 17:00:00 1789.76 1790.45 1780.95 1783.30             0        0             0 +[3] 2021.08.17 18:00:00 1783.30 1783.98 1780.53 1782.73             0        0             0 +[4] 2021.08.17 19:00:00 1782.69 1784.16 1782.09 1782.49             0        0             0 +[5] 2021.08.17 20:00:00 1782.49 1786.23 1782.17 1784.23             0        0             0 +[6] 2021.08.17 21:00:00 1784.20 1784.85 1782.73 1783.12             0        0             0 +[7] 2021.08.17 22:00:00 1783.10 1785.52 1782.37 1785.16             0        0             0 +[8] 2021.08.17 23:00:00 1785.11 1785.84 1784.71 1785.80             0        0             0 +[9] 2021.08.18 01:00:00 1786.30 1786.34 1786.18 1786.20             0        0             0 + +``` + +It is easy to make sure that the data is stored and read correctly. And now let's see how they look inside the file: + +![Viewing the internal structure of a binary file with an archive of quotes in an external program](pics/objectraw.png) + +Viewing the internal structure of a binary file with an archive of quotes in an external program + +Here, various fields of our header are highlighted with color: signature, symbol name length, symbol name, timeframe name, etc. diff --git a/skills/mql5/references/book/03-common/0184-common-files-files-txt-atomic.md b/skills/mql5/references/book/03-common/0184-common-files-files-txt-atomic.md new file mode 100644 index 0000000..14db7f0 --- /dev/null +++ b/skills/mql5/references/book/03-common/0184-common-files-files-txt-atomic.md @@ -0,0 +1,368 @@ +# Writing and reading variables (text files) + +Text files have their own set of functions for atomic (element-by-element) saving and for reading data. It is slightly different from the binary files set in the previous section. It should also be noted that there are no analog functions for writing/reading a structure or an array of structures to a text file. If you try to use any of these functions with a text file, they will have no effect but will raise an internal error code of 5011 (FILE_NOTBIN). + +As we already know, text files in MQL5 have two forms: plain text and text in CSV format. The corresponding mode, FILE_TXT or FILE_CSV, is set when the file is opened and cannot be changed without closing and reacquiring the handle. The difference between them appears only when reading files. Both modes are recorded in the same way. + +In the TXT mode, each call to the read function (any of the functions we'll look at in this section) finds the next newline in the file (a '\n' character or a pair of '\r\n') and processes everything up to it. The point of processing is to convert the text from the file into a value of a specific type corresponding to the called function. In the simplest case, if the FileReadString function is called, no processing is performed (the string is returned "as is"). + +In the CSV mode, each time the read function is called, the text in the file is logically split not only by newlines but also by an additional delimiter specified when opening the file. The rest of the processing of the fragment from the current position of the file to the nearest delimiter is similar. + +In other words, reading the text and transferring the internal position within the file is done in fragments from delimiter to delimiter, where delimiter means not only the delimiter character in the FileOpen parameter list but also a newline ('\n', '\r\n'), as well as the beginning and end of the file. + +The additional delimiter has the same effect on writing text to FILE_TXT and FILE_CSV files, but only when using the FileWrite function: it automatically inserts this character between the recorded elements. The FileWriteString function separator is ignored. + +Let's view the formal descriptions of the functions, and then consider an example in FileTxtCsv.mq5. + +uint FileWrite(int handle, ...) + +The function belongs to the category of functions that take a variable number of parameters. Such parameters are indicated in the function prototype with an ellipsis. Only built-in data types are supported. To write structures or class objects, you must dereference their elements and pass them individually. + +The function writes all arguments passed after the first one to a text file with the handle descriptor. Arguments are separated by commas, as in a normal argument list. The number of arguments output to the file cannot exceed 63. + +When output, numeric data is converted to text format according to the rules of the standard conversion to (string). Values or type double output to 16 significant digits, either in traditional format or scientific exponent format (the more compact option is chosen). Data of the float type is displayed with an accuracy of 7 significant digits. To display real numbers with a different precision or in an explicitly specified format, use the DoubleToString function (see [Numbers to strings and vice versa](/en/book/common/conversions/conversions_numbers)). + +Values of the datetime type are output in the format "YYYY.MM.DD hh:mm:ss" (see [Date and time](/en/book/common/conversions/conversions_datetime)). + +A standard color (from the list of web colors) is displayed as a name, a non-standard color is displayed as a triple of RGB component values (see [Color](/en/book/common/conversions/conversions_color)), separated by commas (note: comma is the most common separator character in CSV). + +For enumerations, an integer denoting the element is displayed instead of its identifier (name). For example, when writing FRIDAY (from ENUM_DAY_OF_WEEK, see [Enumerations](/en/book/basis/builtin_types/enums)) we get number 5 in the file. + +Values of the bool type are output as the strings "true" or "false". + +If a delimiter character other than 0 was specified when opening the file, it will be inserted between two adjacent lines resulting from the conversion of the corresponding arguments. + +Once all arguments are written to the file, a line terminator '\r\n' is added. + +The function returns the number of bytes written, or 0 in case of an error. + +uint FileWriteString(int handle, const string text, int length = -1) + +The function writes the text string parameter to a text file with the handle descriptor. The length parameter is only applicable for binary files and is ignored in this context (the line is written in full). + +The FileWriteString function can also work with binary files. This application of the function is described in the previous section. + +Any separators (between elements in a line) and newlines must be inserted/added by the programmer. + +The function returns the number of bytes written (in FILE_UNICODE mode this will be 2 times the length of the string in characters) or 0 in case of an error. + +string FileReadString(int handle, int length = -1) + +The function reads a string up to the next delimiter from a file with the handle descriptor (delimiter character in a CSV file, linefeed character in any file, or until the end of the file). The length parameter only applies to binary files and is ignored in this context. + +The resulting string can be converted to a value of the required type using standard [reduction rules](/en/book/basis/conversion/conversion_explicit) or using [conversion functions](/en/book/common/conversions). Alternatively, specialized read functions can be used: FileReadBool, FileReadDatetime, FileReadNumber are described below. + +In case of an error, an empty string will be returned. The error code can be found through the variable _LastError or function [GetLastError](/en/book/common/environment/env_last_error). In particular, when the end of the file is reached, the error code will be 5027 (FILE_ENDOFFILE). + +bool FileReadBool(int handle) + +The function reads a fragment of a CSV file up to the next delimiter, or until the end of the line and converts it to a value of type bool. If the fragment contains the text "true" (in any case, including mixed case, for example, "True"), or a non-zero number, we get true. In other cases, we get false. + +The word "true" must occupy the entire read element. Even if the string starts with "true", but has a continuation (for example, "True Volume"), we get false. + +datetime FileReadDatetime(int handle) + +The function reads from a CSV file a string of one of the following formats: "YYYY.MM.DD hh:mm:ss", "YYYY.MM.DD" or "hh:mm:ss", and converts it to a value of the datetime type. If the fragment does not contain a valid textual representation of the date and/or time, the function will return zero or "weird" time, depending on what characters it can interpret as date and time fragments. For empty or non-numeric strings, we get the current date with zero time. + +More flexible date and time reading (with more formats supported) can be achieved by combining two functions: StringToTime(FileReadString(handle)). For further details about StringToTime see [Date and time](/en/book/common/conversions/conversions_datetime). + +double FileReadNumber(int handle) + +The function reads a fragment from the CSV file up to the next delimiter or until the end of the line, and converts it to a value of type double according to standard [type casting](/en/book/common/conversions/conversions_numbers) rules. + +Please note that the double may lose the precision of very large values, which can affect the reading of large numbers of types long/ulong (the value after which integers inside double are distorted is 9007199254740992: an example of such a phenomenon is given in the section [Unions](/en/book/oop/structs_and_unions/unions)). + +Functions discussed in the previous section, including FileReadDouble, FileReadFloat, FileReadInteger, FileReadLong, and FileReadStruct, cannot be applied to text files. + +The FileTxtCsv.mq5 script demonstrates how to work with text files. Last time we uploaded quotes to a binary file. Now let's do it in TXT and CSV formats. + +Basically, MetaTrader 5 allows you to export and import quotes in CSV format from the "Symbols" dialog. But for educational purposes, we will reproduce this process. In addition, the software implementation allows you to deviate from the exact format that is generated by default. A fragment of the XAUUSD H1 history exported in the standard way is shown below. + +``` + »