diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 000000000..9351e96b7 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,21 @@ +--- +# CodeRabbit configuration +version: 1 +reviews: + request_changes_workflow: false + auto_review: + enabled: true + ignore_title_patterns: + - "WIP" + - "DO NOT MERGE" + drafts: false + base_branches: + - "master" + - "v*" + path_filters: + - "**/*.yml" + tools: + yamllint: + enabled: true + shellcheck: + enabled: true diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 1e2528400..9b8d3f2af 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,36 +3,41 @@ { // "build": { - // "dockerfile": "Dockerfile", - // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 - // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. - // "args": { "VARIANT": "ubuntu-22.04" } + // "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 + // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. + // "args": { "VARIANT": "ubuntu-22.04" } // }, - // Configure tool-specific properties. - "customizations": { + // Configure tool-specific properties. + "customizations": { "vscode": { "extensions": [ - "ms-vscode.cpptools", - "ms-vscode.cpptools-extension-pack", - "nicholishen.mql-over-cpp", - "vscodevim.vim", - "DavidAnson.vscode-markdownlint", - "EA31337.vscode-mql-tools", - "xaver.clang-format" - ], - } + "DavidAnson.vscode-markdownlint", + "EA31337.vscode-mql-tools", + "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack", + "nicholishen.mql-over-cpp", + "vscodevim.vim", + "xaver.clang-format", + "GitHub.copilot", + "GitHub.copilot-chat" + ] + } }, // Features to add to the dev container. More info: https://containers.dev/features. - "features": { - "ghcr.io/devcontainers-contrib/features/actionlint:1": {}, - "ghcr.io/guiyomh/features/vim:0": {}, - "ghcr.io/jungaretti/features/make:1": {}, - "ghcr.io/prulloac/devcontainer-features/pre-commit:1": {}, - "ghcr.io/hspaans/devcontainer-features/ansible-lint:1": {}, - // "ghcr.io/maks1ms/devcontainers-features/wine:0": {}, - "ghcr.io/devcontainers-contrib/features/node-asdf:0": {} - }, + "features": { + "ghcr.io/devcontainers-contrib/features/actionlint:1": {}, + "ghcr.io/devcontainers-contrib/features/node-asdf:0": {}, + "ghcr.io/devcontainers-extra/features/pipx-package:1": {}, + "ghcr.io/devcontainers/features/docker-in-docker:2": {}, + "ghcr.io/devcontainers/features/python:1": {}, + "ghcr.io/guiyomh/features/vim:0": {}, + "ghcr.io/jungaretti/features/make:1": {}, + "ghcr.io/prulloac/devcontainer-features/pre-commit:1": {}, + "ghcr.io/jungaretti/features/ripgrep:1": {} + // "ghcr.io/maks1ms/devcontainers-features/wine:0": {} + }, // Use 'forwardPorts' to make a list of ports inside the container available locally. // "forwardPorts": [], @@ -44,6 +49,8 @@ "image": "mcr.microsoft.com/devcontainers/base:jammy", "name": "EA31337", + "postCreateCommand": "pip install -r .devcontainer/requirements.txt", + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. "remoteUser": "vscode", "onCreateCommand": "sudo apt update && sudo apt install -y pipx && pipx install --include-deps ansible" diff --git a/.github/workflows/test-exchange-account.yml b/.github/workflows/test-exchange-account.yml index 05d73df32..f1251beb4 100644 --- a/.github/workflows/test-exchange-account.yml +++ b/.github/workflows/test-exchange-account.yml @@ -3,7 +3,7 @@ name: Test Exchange/Account env: TEST_PATH: Exchange/Account/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -48,7 +48,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -64,7 +64,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-exchange-symbolinfo.yml b/.github/workflows/test-exchange-symbolinfo.yml index d9640c624..62837373b 100644 --- a/.github/workflows/test-exchange-symbolinfo.yml +++ b/.github/workflows/test-exchange-symbolinfo.yml @@ -3,7 +3,7 @@ name: Test Exchange/SymbolInfo env: TEST_PATH: Exchange/SymbolInfo/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -46,7 +46,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -62,7 +62,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-exchange.yml b/.github/workflows/test-exchange.yml index eabe553a1..2132f709c 100644 --- a/.github/workflows/test-exchange.yml +++ b/.github/workflows/test-exchange.yml @@ -3,7 +3,7 @@ name: Test Exchange env: TEST_PATH: Exchange/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -48,7 +48,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -64,7 +64,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicator.yml b/.github/workflows/test-indicator.yml index 1504084fb..bbd27be22 100644 --- a/.github/workflows/test-indicator.yml +++ b/.github/workflows/test-indicator.yml @@ -3,7 +3,7 @@ name: Test Indicator env: TEST_PATH: Indicator/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -54,7 +54,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -70,7 +70,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicators-bitwise.yml b/.github/workflows/test-indicators-bitwise.yml index e7356f1bb..dc387d6b3 100644 --- a/.github/workflows/test-indicators-bitwise.yml +++ b/.github/workflows/test-indicators-bitwise.yml @@ -3,7 +3,7 @@ name: Test Indicators (Bitwise) env: TEST_PATH: Indicators/Bitwise/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -49,7 +49,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -65,7 +65,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicators-ohlc.yml b/.github/workflows/test-indicators-ohlc.yml index 07ebb0323..7c1845d93 100644 --- a/.github/workflows/test-indicators-ohlc.yml +++ b/.github/workflows/test-indicators-ohlc.yml @@ -3,7 +3,7 @@ name: Test Indicators (OHLC) env: TEST_PATH: Indicators/OHLC/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -48,7 +48,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -64,7 +64,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicators-oscillator.yml b/.github/workflows/test-indicators-oscillator.yml index 73dd58bd6..94123f76a 100644 --- a/.github/workflows/test-indicators-oscillator.yml +++ b/.github/workflows/test-indicators-oscillator.yml @@ -3,7 +3,7 @@ name: Test Indicators (Oscillator) env: TEST_PATH: Indicators/Oscillator/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -51,7 +51,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -67,7 +67,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicators-price.yml b/.github/workflows/test-indicators-price.yml index c5339ecfb..1e3e54a50 100644 --- a/.github/workflows/test-indicators-price.yml +++ b/.github/workflows/test-indicators-price.yml @@ -3,7 +3,7 @@ name: Test Indicators (Price) env: TEST_PATH: Indicators/Price/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -50,7 +50,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -66,7 +66,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicators-pricemulti.yml b/.github/workflows/test-indicators-pricemulti.yml index 549ecb6b8..6e1e3bea0 100644 --- a/.github/workflows/test-indicators-pricemulti.yml +++ b/.github/workflows/test-indicators-pricemulti.yml @@ -3,7 +3,7 @@ name: Test Indicators (PriceMulti) env: TEST_PATH: Indicators/PriceMulti/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -48,7 +48,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -64,7 +64,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicators-pricerange.yml b/.github/workflows/test-indicators-pricerange.yml index 9e22cfcac..2dde68202 100644 --- a/.github/workflows/test-indicators-pricerange.yml +++ b/.github/workflows/test-indicators-pricerange.yml @@ -3,7 +3,7 @@ name: Test Indicators (PriceRange) env: TEST_PATH: Indicators/PriceRange/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -51,7 +51,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -67,7 +67,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicators-special.yml b/.github/workflows/test-indicators-special.yml index 817ca9aaf..149a1de30 100644 --- a/.github/workflows/test-indicators-special.yml +++ b/.github/workflows/test-indicators-special.yml @@ -3,7 +3,7 @@ name: Test Indicators (Special) env: TEST_PATH: Indicators/Special/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -49,7 +49,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -65,7 +65,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicators-tick.yml b/.github/workflows/test-indicators-tick.yml index 07f158ba7..2aa8d9725 100644 --- a/.github/workflows/test-indicators-tick.yml +++ b/.github/workflows/test-indicators-tick.yml @@ -3,7 +3,7 @@ name: Test Indicators (Tick) env: TEST_PATH: Indicators/Tick/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -48,7 +48,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -64,7 +64,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-indicators.yml b/.github/workflows/test-indicators.yml index 1e1e7945f..fe9c796de 100644 --- a/.github/workflows/test-indicators.yml +++ b/.github/workflows/test-indicators.yml @@ -3,7 +3,7 @@ name: Test Indicators env: TEST_PATH: Indicators/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -98,7 +98,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -114,7 +114,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-math.yml b/.github/workflows/test-math.yml index f1dc64589..7877e6202 100644 --- a/.github/workflows/test-math.yml +++ b/.github/workflows/test-math.yml @@ -3,7 +3,7 @@ name: Test Math env: TEST_PATH: Math/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -48,7 +48,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -64,7 +64,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-platform-chart.yml b/.github/workflows/test-platform-chart.yml index d85a9dded..8709a2638 100644 --- a/.github/workflows/test-platform-chart.yml +++ b/.github/workflows/test-platform-chart.yml @@ -3,7 +3,7 @@ name: Test Platform/Chart env: TEST_PATH: Platform/Chart/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -47,7 +47,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -63,7 +63,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-platform-chart3d.yml b/.github/workflows/test-platform-chart3d.yml index 05c3f4a87..cd22e17d1 100644 --- a/.github/workflows/test-platform-chart3d.yml +++ b/.github/workflows/test-platform-chart3d.yml @@ -3,7 +3,7 @@ name: Test Platform/Chart3D env: TEST_PATH: Platform/Chart3D/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -46,7 +46,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -63,7 +63,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 30 diff --git a/.github/workflows/test-platform-web.yml b/.github/workflows/test-platform-web.yml index afd4b9e57..143e52e83 100644 --- a/.github/workflows/test-platform-web.yml +++ b/.github/workflows/test-platform-web.yml @@ -3,7 +3,7 @@ name: Test Platform/Web env: TEST_PATH: Platform/Web/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -47,7 +47,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -63,7 +63,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-platform.yml b/.github/workflows/test-platform.yml index 37388ba03..b93eaa308 100644 --- a/.github/workflows/test-platform.yml +++ b/.github/workflows/test-platform.yml @@ -3,7 +3,7 @@ name: Test Platform env: TEST_PATH: Platform/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -51,7 +51,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -67,7 +67,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-serializer.yml b/.github/workflows/test-serializer.yml index a256229e8..57613112d 100644 --- a/.github/workflows/test-serializer.yml +++ b/.github/workflows/test-serializer.yml @@ -3,7 +3,7 @@ name: Test Serializer env: TEST_PATH: Serializer/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -46,7 +46,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -62,7 +62,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-storage-cache.yml b/.github/workflows/test-storage-cache.yml index c4649601d..1a5371990 100644 --- a/.github/workflows/test-storage-cache.yml +++ b/.github/workflows/test-storage-cache.yml @@ -3,7 +3,7 @@ name: Test Storage/Cache env: TEST_PATH: Storage/Cache/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -47,7 +47,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -63,7 +63,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-storage-dict-buffer.yml b/.github/workflows/test-storage-dict-buffer.yml index 842a1ec5b..032270bcd 100644 --- a/.github/workflows/test-storage-dict-buffer.yml +++ b/.github/workflows/test-storage-dict-buffer.yml @@ -3,7 +3,7 @@ name: Test Storage/Dict/Buffer env: TEST_PATH: Storage/Dict/Buffer/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -51,7 +51,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -67,7 +67,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-storage-dict.yml b/.github/workflows/test-storage-dict.yml index e9f62d7ae..ecc77bb8b 100644 --- a/.github/workflows/test-storage-dict.yml +++ b/.github/workflows/test-storage-dict.yml @@ -3,7 +3,7 @@ name: Test Storage/Dict env: TEST_PATH: Storage/Dict/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -46,7 +46,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -62,7 +62,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-storage.yml b/.github/workflows/test-storage.yml index 2ee696439..5b3b795c0 100644 --- a/.github/workflows/test-storage.yml +++ b/.github/workflows/test-storage.yml @@ -3,7 +3,7 @@ name: Test Storage env: TEST_PATH: Storage/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -40,6 +40,7 @@ jobs: - Collection.test - Database.test - DateTime.test + - Instances.test - ItemsHistory.test - Object.test - Redis.test @@ -52,7 +53,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -68,7 +69,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-strategy.yml b/.github/workflows/test-strategy.yml new file mode 100644 index 000000000..bc5c78103 --- /dev/null +++ b/.github/workflows/test-strategy.yml @@ -0,0 +1,73 @@ +--- +name: Test Strategy + +env: + TEST_PATH: Strategy/tests + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} + +# yamllint disable-line rule:truthy +on: + pull_request: + paths: + - .github/workflows/test-strategy.yml + - Strategy/** + push: + paths: + - .github/workflows/test-strategy.yml + - Strategy/** + +jobs: + + compile: + name: Compile + uses: ./.github/workflows/compile-mql.yml + with: + artifact_prefix: mt + path: Strategy/tests + skip_cleanup: true + + test: + defaults: + run: + shell: bash + working-directory: ${{ env.TEST_PATH }} + name: Test + needs: compile + runs-on: ubuntu-latest + strategy: + matrix: + test: + - Strategy.test + - Strategy-RSI.test + version: [5] + max-parallel: 4 + steps: + - uses: actions/download-artifact@v4 + with: + name: files-ex${{ matrix.version }} + - name: List compiled files + run: find . -name '*.ex?' -type f -print + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} + name: Run ${{ matrix.test }} + uses: fx31337/mql-tester-action@master + with: + Login: ${{ secrets.MT5_LOGIN }} + Password: ${{ secrets.MT5_PASSWORD }} + Server: MetaQuotes-Demo + TestDeposit: 2000 + TestExpert: ${{ matrix.test }} + TestFromDate: ${{ matrix.year }}.01.01 + TestPeriod: M1 + TestSymbol: EURUSD + TestToDate: ${{ matrix.year }}.01.14 + # yamllint disable-line rule:line-length + UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} + Version: 5 + - if: ${{ failure() && runner.debug == '1' }} + uses: mxschmitt/action-tmate@v3 + timeout-minutes: 20 + + cleanup: + name: Clean-up + needs: [compile] + uses: ./.github/workflows/cleanup.yml diff --git a/.github/workflows/test-task.yml b/.github/workflows/test-task.yml index 239753e58..cad05bc56 100644 --- a/.github/workflows/test-task.yml +++ b/.github/workflows/test-task.yml @@ -3,7 +3,7 @@ name: Test Task env: TEST_PATH: Task/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -54,7 +54,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -70,7 +70,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test-trade.yml b/.github/workflows/test-trade.yml index 2f16435b5..f3c1457c3 100644 --- a/.github/workflows/test-trade.yml +++ b/.github/workflows/test-trade.yml @@ -3,7 +3,7 @@ name: Test Trade env: TEST_PATH: Trade/tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -49,7 +49,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -65,7 +65,7 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a97047d2b..0e6f9f544 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,7 +3,7 @@ name: Test env: TEST_PATH: tests - TEST_SKIP: ${{ secrets.MT5_LOGIN || false }} + TEST_SKIP: ${{ secrets.MT5_LOGIN == '' }} # yamllint disable-line rule:truthy on: @@ -46,10 +46,9 @@ jobs: - EATest - MailTest - MarketTest - - StrategyTest - - StrategyTest-RSI - SummaryReportTest - TradeTest + year: [2022, 2024] version: [5] max-parallel: 4 steps: @@ -58,7 +57,7 @@ jobs: name: files-ex${{ matrix.version }} - name: List compiled files run: find . -name '*.ex?' -type f -print - - if: ${{ env.TEST_SKIP != true }} + - if: ${{ env.TEST_SKIP != true && env.TEST_SKIP != 'true' }} name: Run ${{ matrix.test }} uses: fx31337/mql-tester-action@master with: @@ -74,7 +73,8 @@ jobs: # yamllint disable-line rule:line-length UrlExpert: file://${{ github.workspace }}/${{ env.TEST_PATH }}/${{ matrix.test }}.ex${{ matrix.version }} Version: 5 - - if: ${{ failure() && runner.debug }} + RunnerTimeout: 1200 + - if: ${{ failure() && runner.debug == '1' }} uses: mxschmitt/action-tmate@v3 timeout-minutes: 20 diff --git a/.vscode/settings.json b/.vscode/settings.json index 7417eab66..bb0dddd03 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,8 @@ { "files.associations": { - "indicatorcandle.h": "c", - "*.mqh": "c" + "*.h": "cpp", + "*.mq4": "cpp", + "*.mq5": "cpp", + "*.mqh": "cpp" } } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6dc12782a..480ea4df3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,23 +26,44 @@ We use a `clang-format` code formatter tool to format the code For example, to format file inplace, run: - clang-format -i File.mqh + clang-format -i File.h ### Syntax To improve code compatibility, please use the following syntax: -| MQL | C++ | Syntax to use | -|:------------------|:------------------------|:---------------------------| -| `&this` | `this` | `THIS_PTR` | -| `GetPointer(obj)` | `*obj` | `GET_PTR(obj)` | -| `T name[]` | `_cpp_array name` | `ARRAY(T, name)` | -| `T N[]` | `_cpp_array> N` | `ARRAY(T, N)` | -| `obj.Method()` | `obj->Method()` | `obj PTR_DEREF Method()` | -| `obj.Ptr().a` | `obj.Ptr()->a` | `obj REF_DEREF a` | -| `obj.a1.a2` | `obj->a1->a2` | `PTR_ATTRIB2(obj, a1, a2)` | -| `obj.attr` | `obj->attr` | `PTR_ATTRIB(obj, attr)` | -| `str == NULL` | `str == NULL` | `IsNull(str)` | +| MQL | C++ | Syntax to use | +|:-------------------|:-------------------------|:---------------------------| +| `&this` | `this` | `THIS_PTR` | +| `this` | `*this` | `THIS_REF` | +| `GetPointer(obj)` | `&obj` | `GET_PTR(obj)` | +| `T name[]` | `std::vector name` | `ARRAY(T, name)` | +| `T name[5]` | `T name[5]` | `FIXED_ARRAY(T, name, 5)` | +| `X f(T[] v)` ⁵| `X f(T(&n)[5])` | `FIXED_ARRAY_REF(T, n, 5)` | +| `T name[]` | `vector> name` | `ARRAY(T, N)` | +| `long` | `long long` | `int64` | +| `unsigned long` | `unsigned long long` | `uint64` | +| `obj.Method()` ¹| `obj->Method()` | `obj PTR_DEREF Method()` | +| `obj.Ptr().a` ³| `obj.Ptr()->a` | `obj REF_DEREF a` | +| `obj.a1.a2` ¹| `obj->a1->a2` | `PTR_ATTRIB2(obj, a1, a2)` | +| `obj.attr` ¹| `obj->attr` | `PTR_ATTRIB(obj, attr)` | +| `str == NULL` | `str == NULL` | `IsNull(str)` | +| `foo((Ba&)obj)` ²| `foo(*obj)` | `foo(PTR_TO_REF(obj))` | +| `foo((Ba*)obj)` ¹| `foo(&obj)` | `foo(REF_TO_PTR(obj))` | +| `void* N` ⁴| `void*& N[]` | `VOID_DATA(N)` | +| `int foo` ⁵| `const int foo` | `CONST_CPP int foo` | +| `int foo(int v)` ⁵| `int foo(int& v)` | `int foo(int REF_CPP v)` | +| `X foo()` ⁵| `X& foo()` | `X REF_CPP foo()` | +| `obj == NULL` ¹| `obj == nullptr` | `obj == nullptr` | +| `datetime d = NULL`| `datetime d = 0` | `datetime = 0` | + +Footnotes: + +* ¹ Only if `obj` is a pointer. +* ² Only if `obj` is an object or reference type (e.g., `Foo &`). +* ³ Only if `obj` is `Ref`. +* ⁴ Only when used as a parameter to function. +* ⁵ In C++ we could want to return structure by reference or add `const` to the variable or result. ## Proposing changes diff --git a/EA.mqh b/EA.mqh index b894673d4..21f7aec76 100644 --- a/EA.mqh +++ b/EA.mqh @@ -46,7 +46,7 @@ #include "Storage/Data.struct.h" #include "Storage/Dict/Dict.h" #include "Storage/Dict/DictObject.h" -#include "Strategy.mqh" +#include "Strategy/Strategy.h" #include "SummaryReport.mqh" #include "Task/Task.h" #include "Task/TaskAction.enum.h" @@ -70,7 +70,7 @@ class EA : public Taskable { BufferStruct data_symbol; Dict ddata; // Custom user data. Dict idata; // Custom user data. - DictObject trade; + DictStruct> trade; DictObject> data_indi; DictObject> data_stg; EAParams eparams; @@ -98,8 +98,7 @@ class EA : public Taskable { void InitTask() { // Add and process init task. TaskEntry _task_entry(eparams.GetStruct(STRUCT_ENUM(EAParams, EA_PARAM_STRUCT_TASK_ENTRY))); - TaskObject _taskobj_init(_task_entry, - THIS_PTR, THIS_PTR); + TaskObject _taskobj_init(_task_entry, THIS_PTR, THIS_PTR); estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), true); _taskobj_init.Process(); estate.Set(STRUCT_ENUM(EAState, EA_STATE_FLAG_ON_INIT), false); @@ -115,11 +114,11 @@ class EA : public Taskable { // Add and process tasks. Init(); // Initialize a trade instance for the current chart and symbol. - Ref _source = Platform::FetchDefaultCandleIndicator(_Symbol, PERIOD_CURRENT); + Ref _source = Platform::FetchDefaultCandleIndicator(Platform::GetSymbol(), Platform::GetPeriod()); TradeParams _tparams(0, 1.0f, 0, (ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); - Trade _trade(_tparams, _source.Ptr()); + Ref _trade = new Trade(_tparams, _source.Ptr()); trade.Set(_Symbol, _trade); - logger.Link(_trade.GetLogger()); + logger.Link(_trade REF_DEREF GetLogger()); logger.SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); //_trade.GetLogger().SetLevel((ENUM_LOG_LEVEL)eparams.Get(STRUCT_ENUM(EAParams, EA_PARAM_PROP_LOG_LEVEL))); } @@ -163,7 +162,7 @@ class EA : public Taskable { */ template T Get(ENUM_TRADE_STATE _state, string _symbol = NULL) { - return trade.GetByKey(_symbol != "" ? _symbol : _Symbol) PTR_DEREF Get(_state); + return trade.GetByKey(_symbol != "" ? _symbol : _Symbol) REF_DEREF Get(_state); } /** @@ -221,7 +220,7 @@ class EA : public Taskable { /** * Gets EA's trade instance. */ - Trade *GetTrade(string _symbol) { return trade.GetByKey(_symbol); } + Trade *GetTrade(string _symbol) { return trade.GetByKey(_symbol).Ptr(); } /* Setters */ @@ -254,8 +253,8 @@ class EA : public Taskable { */ template void Set(ENUM_TRADE_PARAM _param, T _value) { - for (DictObjectIterator iter = trade.Begin(); iter.IsValid(); ++iter) { - Trade *_trade = iter.Value(); + for (DictStructIterator> iter = trade.Begin(); iter.IsValid(); ++iter) { + Trade *_trade = iter.Value().Ptr(); _trade PTR_DEREF Set(_param, _value); } for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { @@ -280,7 +279,7 @@ class EA : public Taskable { // Ignores already processed signals. continue; } - Trade *_trade = trade.GetByKey(_Symbol); + Trade *_trade = trade.GetByKey(_Symbol).Ptr(); Strategy *_strat = strats.GetByKey(_signal PTR_DEREF Get(STRUCT_ENUM(TradeSignalEntry, TRADE_SIGNAL_PROP_MAGIC_ID))) .Ptr(); @@ -387,7 +386,7 @@ class EA : public Taskable { */ virtual bool TradeRequest(ENUM_ORDER_TYPE _cmd, string _symbol = NULL, Strategy *_strat = NULL) { bool _result = false; - Trade *_trade = trade.GetByKey(_symbol); + Trade *_trade = trade.GetByKey(_symbol).Ptr(); // Prepare a request. MqlTradeRequest _request = _trade PTR_DEREF GetTradeOpenRequest(_cmd); _request.comment = _strat PTR_DEREF GetOrderOpenComment(); @@ -453,7 +452,7 @@ class EA : public Taskable { for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { bool _can_trade = true; Strategy *_strat = iter.Value().Ptr(); - Trade *_trade = trade.GetByKey(_Symbol); + Trade *_trade = trade.GetByKey(_Symbol).Ptr(); if (_strat PTR_DEREF IsEnabled()) { if (estate.Get(STRUCT_ENUM(EAState, EA_STATE_PROP_NEW_PERIODS)) >= DATETIME_MINUTE) { // Process when new periods started. @@ -600,9 +599,10 @@ class EA : public Taskable { SerializerConverter _stub = SerializerConverter::MakeStubObject>(_serializer_flags); - /* - for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { - ENUM_TIMEFRAMES _itf = iter_tf.Key(); // @fixme + /* @todo + for (DictStructIterator> _iter = GetStrategies() PTR_DEREF Begin(); _iter.IsValid(); ++_iter) + { int _sid = (int)_iter.Key(); Strategy *_strat = _iter.Value().Ptr(); + // ENUM_TIMEFRAMES _itf = iter_tf.Key(); // @fixme if (data_indi.KeyExists(_itf)) { BufferStruct _indi_buff = data_indi.GetByKey(_itf); @@ -635,15 +635,16 @@ class EA : public Taskable { if (eparams.CheckFlagDataStore(EA_DATA_STORE_STRATEGY)) { SerializerConverter _stub = SerializerConverter::MakeStubObject>(_serializer_flags); - /* @fixme - for (DictStructIterator> iter = strats.Begin(); iter.IsValid(); ++iter) { - ENUM_TIMEFRAMES _stf = iter_tf.Key(); // @fixme - if (data_stg.KeyExists(_stf)) { - string _key_stg = StringFormat("Strategy-%d", _stf); - BufferStruct _stg_buff = data_stg.GetByKey(_stf); - SerializerConverter _obj = SerializerConverter::FromObject(_stg_buff, _serializer_flags); + for (DictStructIterator> _iter = GetStrategies() PTR_DEREF Begin(); _iter.IsValid(); + ++_iter) { + int _sid = (int)_iter.Key(); + Strategy *_strat = _iter.Value().Ptr(); + if (data_stg.KeyExists(_sid)) { + string _key_stg = StringFormat("Strategy-%d", _sid); + BufferStruct *_stg_buff = data_stg.GetByKey(_sid); + SerializerConverter _obj = SerializerConverter::FromObject(PTR_TO_REF(_stg_buff), _serializer_flags); - _key_stg += StringFormat("-%d-%d-%d", _stf, _stg_buff.GetMin(), _stg_buff.GetMax()); + _key_stg += StringFormat("-%d-%d-%d", _sid, _stg_buff PTR_DEREF GetMin(), _stg_buff PTR_DEREF GetMax()); if ((_methods & EA_DATA_EXPORT_CSV) != 0) { _obj.ToFile(_key_stg + ".csv", _serializer_flags, &_stub); } @@ -658,7 +659,6 @@ class EA : public Taskable { _obj.Clean(); } } - */ // Required because of SERIALIZER_FLAG_REUSE_STUB flag. _stub.Clean(); } @@ -825,7 +825,7 @@ class EA : public Taskable { */ bool StrategyLoadTrades(Strategy *_strat) { bool _result = true; - Trade *_trade = trade.GetByKey(_Symbol); + Trade *_trade = trade.GetByKey(_Symbol).Ptr(); // Load active trades. _result &= _trade PTR_DEREF OrdersLoadByMagic(_strat PTR_DEREF Get(STRAT_PARAM_ID)); // Load strategy-specific order parameters (e.g. conditions). @@ -853,8 +853,8 @@ class EA : public Taskable { bool ProcessTrades() { bool _result = true; ResetLastError(); - for (DictObjectIterator titer = trade.Begin(); titer.IsValid(); ++titer) { - Trade *_trade = titer.Value(); + for (DictStructIterator> titer = trade.Begin(); titer.IsValid(); ++titer) { + Trade *_trade = titer.Value().Ptr(); if (_trade PTR_DEREF Get(TRADE_STATE_ORDERS_ACTIVE) && !_trade PTR_DEREF Get(TRADE_STATE_MARKET_CLOSED)) { for (DictStructIterator> oiter = _trade PTR_DEREF GetOrdersActive() PTR_DEREF Begin(); @@ -951,7 +951,7 @@ class EA : public Taskable { bool _result = false; if (eparams.CheckFlag(EA_PARAM_FLAG_LOTSIZE_AUTO)) { // Auto calculate lot size for all strategies. - Trade *_trade = trade.GetByKey(_Symbol); + Trade *_trade = trade.GetByKey(_Symbol).Ptr(); _result &= _trade PTR_DEREF Run(TRADE_ACTION_CALC_LOT_SIZE); Set(STRAT_PARAM_LS, _trade PTR_DEREF Get(TRADE_PARAM_LOT_SIZE)); } @@ -1043,13 +1043,13 @@ class EA : public Taskable { switch (_entry.GetId()) { case EA_ACTION_DISABLE: estate.Enable(false); - return true; + break; case EA_ACTION_ENABLE: estate.Enable(); - return true; + break; case EA_ACTION_EXPORT_DATA: DataExport(); - return true; + break; case EA_ACTION_STRATS_EXE_ACTION: { // Args: // 1st (i:0) - Strategy's enum action to execute. @@ -1058,10 +1058,9 @@ class EA : public Taskable { _entry_strat.ArgRemove(0); for (DictStructIterator> iter_strat = strats.Begin(); iter_strat.IsValid(); ++iter_strat) { Strategy *_strat = iter_strat.Value().Ptr(); - _result &= _strat PTR_DEREF Run(_entry_strat); } - return _result; + break; } case EA_ACTION_TASKS_CLEAN: tasks.GetTasks() PTR_DEREF Clear(); @@ -1069,6 +1068,7 @@ class EA : public Taskable { default: GetLogger() PTR_DEREF Error(StringFormat("Invalid EA action: %d!", _entry.GetId(), __FUNCTION_LINE__)); SetUserError(ERR_INVALID_PARAMETER); + _result = false; } return _result; } diff --git a/Exchange/Account/Account.enum.h b/Exchange/Account/Account.enum.h index 9d6246b8d..b1198b1b5 100644 --- a/Exchange/Account/Account.enum.h +++ b/Exchange/Account/Account.enum.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif /* Account type of values for statistics. */ @@ -50,6 +50,20 @@ enum ENUM_ACC_STAT_TYPE { ACC_VALUE_MIN = 0, ACC_VALUE_MAX = 1, ACC_VALUE_AVG = /* Account type of index for statistics. */ enum ENUM_ACC_STAT_INDEX { ACC_VALUE_CURR = 0, ACC_VALUE_PREV = 1, FINAL_ENUM_ACC_STAT_INDEX = 2 }; +#ifndef __MQL5__ +/** + * Enumeration for the margin modes. + * + * @docs + * https://www.mql5.com/en/docs/constants/environment_state/accountinformation + */ +enum ENUM_ACCOUNT_MARGIN_MODE { + ACCOUNT_MARGIN_MODE_EXCHANGE, // Used for the exchange markets to calculate margin based on the discounts. + ACCOUNT_MARGIN_MODE_RETAIL_HEDGING, // Used for the exchange markets where individual positions are possible. + ACCOUNT_MARGIN_MODE_RETAIL_NETTING, // Used for the OTC markets to interpret positions in the "netting" mode. +}; +#endif + #ifndef __MQL__ /** * Enumeration for the current account double values. @@ -112,18 +126,6 @@ enum ENUM_ACCOUNT_INFO_STRING { ACCOUNT_SERVER // Trade server name (string). }; -/** - * Enumeration for the margin modes. - * - * @docs - * https://www.mql5.com/en/docs/constants/environment_state/accountinformation - */ -enum ENUM_ACCOUNT_MARGIN_MODE { - ACCOUNT_MARGIN_MODE_EXCHANGE, // Margin is calculated based on the discounts. - ACCOUNT_MARGIN_MODE_RETAIL_HEDGING, // Used for the exchange markets where individual positions are possible. - ACCOUNT_MARGIN_MODE_RETAIL_NETTING, // Used for the OTC markets to interpret positions in the "netting" mode. -}; - /** * Enumeration for the types of accounts on a trade server. * @@ -146,4 +148,34 @@ enum ENUM_ACCOUNT_STOPOUT_MODE { ACCOUNT_STOPOUT_MODE_PERCENT, // Account stop out mode in percents. ACCOUNT_STOPOUT_MODE_MONEY, // Account stop out mode in money. }; + #endif + +// C++ only enum values for ENUM_ACCOUNT_PARAM_INTEGER. Avoids conflicts. +#define ACCOUNT_MARGIN_MODE 100 +#define ACCOUNT_CURRENCY_DIGITS 101 +#define ACCOUNT_FIFO_CLOSE 102 + +/** + * Enumeration for the account integer param values. + * + * Used for function AccountInfoInteger(). + * + * @docs + * https://www.mql5.com/en/docs/constants/environment_state/accountinformation + */ +enum ENUM_ACCOUNT_PARAM_INTEGER { + ACCOUNT_PARAM_LOGIN = ACCOUNT_LOGIN, // Account number (long). + ACCOUNT_PARAM_TRADE_MODE = ACCOUNT_TRADE_MODE, // Account trade mode (ENUM_ACCOUNT_TRADE_MODE). + ACCOUNT_PARAM_LEVERAGE = ACCOUNT_LEVERAGE, // Account leverage (long). + ACCOUNT_PARAM_LIMIT_ORDERS = ACCOUNT_LIMIT_ORDERS, // Maximum allowed number of active pending orders (int). + ACCOUNT_PARAM_MARGIN_SO_MODE = + ACCOUNT_MARGIN_SO_MODE, // Mode for setting the minimal allowed margin (ENUM_ACCOUNT_STOPOUT_MODE). + ACCOUNT_PARAM_TRADE_ALLOWED = ACCOUNT_TRADE_ALLOWED, // Allowed trade for the current account (bool). + ACCOUNT_PARAM_TRADE_EXPERT = ACCOUNT_TRADE_EXPERT, // Allowed trade for an Expert Advisor (bool). + ACCOUNT_PARAM_MARGIN_MODE = ACCOUNT_MARGIN_MODE, // Margin calculation mode (ENUM_ACCOUNT_MARGIN_MODE). + ACCOUNT_PARAM_CURRENCY_DIGITS = + ACCOUNT_CURRENCY_DIGITS, // The number of decimal places in the account currency (int). + ACCOUNT_PARAM_FIFO_CLOSE = + ACCOUNT_FIFO_CLOSE // An indication showing that positions can only be closed by FIFO rule (bool). +}; diff --git a/Exchange/Account/Account.h b/Exchange/Account/Account.h index 3179fc274..a4768ee63 100644 --- a/Exchange/Account/Account.h +++ b/Exchange/Account/Account.h @@ -21,13 +21,14 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. #include "../../Serializer/Serializer.h" #include "../../Storage/Dict/Buffer/BufferStruct.h" +#include "Account.struct.h" #include "AccountBase.h" /** @@ -36,6 +37,7 @@ template class Account : public AccountBase { protected: + AccountParams aparams; AS state; BufferStruct entries; @@ -52,8 +54,31 @@ class Account : public AccountBase { */ Account() { Init(); } + /** + * Class constructor with parameters. + */ + Account(AccountParams &_aparams) : aparams(_aparams) { Init(); } + + /** + * Class copy constructor. + */ + Account(Account &_account) { + state = _account.state; + // @todo: Copy entries. + } + /** * Class deconstructor. */ ~Account() {} + + /* Serializers */ + + /** + * Returns serialized representation of the object instance. + */ + virtual SerializerNodeType Serialize(Serializer &_s) { + _s.PassStruct(THIS_REF, "state", state); + return SerializerNodeObject; + } }; diff --git a/Exchange/Account/Account.struct.h b/Exchange/Account/Account.struct.h index eeb5324ee..a0c4a8218 100644 --- a/Exchange/Account/Account.struct.h +++ b/Exchange/Account/Account.struct.h @@ -26,18 +26,20 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Forward class declaration. class Serializer; // Includes. -#include "Account.enum.h" -#include "../../Serializer/Serializer.h" -#include "../../Serializer/Serializer.enum.h" #include "../../Platform/Terminal.define.h" +#include "../../Serializer/Serializer.enum.h" +#include "../../Serializer/Serializer.h" +#include "../../Serializer/SerializerConverter.h" +#include "../../Serializer/SerializerJson.h" +#include "Account.enum.h" // Struct for account entries. struct AccountEntry { @@ -108,3 +110,149 @@ struct AccountEntry { return WRONG_VALUE; } }; + +// Struct for account parameters. +struct AccountParams { + ENUM_ACCOUNT_MARGIN_MODE margin_mode; + ENUM_ACCOUNT_STOPOUT_MODE margin_so_mode; + ENUM_ACCOUNT_TRADE_MODE trade_mode; + bool trade_allowed, trade_expert; + int currency_digits, fifo_close, leverage, limit_orders, login; + string company, currency, name, server; + + // Default constructor. + AccountParams(int _login = 0, string _name = "Current", string _currency = "USD", string _company = "Unknown", + string _server = "Unknown") + : login(_login), company(_company), currency(_currency), name(_name), server(_server) {} + // Constructor based on JSON string. + AccountParams(string _entry) { SerializerConverter::FromString(_entry).ToStruct(THIS_REF); } + // Copy constructor. + AccountParams(const AccountParams& _aparams) { THIS_REF = _aparams; } + /* Getters */ + template + T Get(ENUM_ACCOUNT_PARAM_INTEGER _param) { + switch (_param) { + case ACCOUNT_PARAM_CURRENCY_DIGITS: + // The number of decimal places in the account currency (int). + return (T)currency_digits; + case ACCOUNT_PARAM_FIFO_CLOSE: + // An indication showing that positions can only be closed by FIFO rule (bool). + return (T)fifo_close; + case ACCOUNT_PARAM_LEVERAGE: + // Account leverage (long). + return (T)leverage; + case ACCOUNT_PARAM_LIMIT_ORDERS: + // Maximum allowed number of active pending orders (int). + return (T)limit_orders; + case ACCOUNT_PARAM_LOGIN: + // Account number (long). + return (T)login; + case ACCOUNT_PARAM_MARGIN_MODE: + // Margin calculation mode (ENUM_ACCOUNT_MARGIN_MODE). + return (T)margin_mode; + case ACCOUNT_PARAM_MARGIN_SO_MODE: + // Mode for setting the minimal allowed margin (ENUM_ACCOUNT_STOPOUT_MODE). + return (T)margin_so_mode; + case ACCOUNT_PARAM_TRADE_ALLOWED: + // Allowed trade for the current account (bool). + return (T)trade_allowed; + case ACCOUNT_PARAM_TRADE_EXPERT: + // Allowed trade for an Expert Advisor (bool). + return (T)trade_expert; + case ACCOUNT_PARAM_TRADE_MODE: + // Account trade mode (ENUM_ACCOUNT_TRADE_MODE). + return (T)trade_mode; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + string Get(ENUM_ACCOUNT_INFO_STRING _param) { + switch (_param) { + case ACCOUNT_NAME: + // Client name (string). + return name; + case ACCOUNT_COMPANY: + // Name of a company that serves the account (string). + return company; + case ACCOUNT_CURRENCY: + // Account currency (string). + return currency; + case ACCOUNT_SERVER: + // Trade server name (string). + return server; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return ""; + } + template + void Set(ENUM_ACCOUNT_PARAM_INTEGER _param, T _value) { + switch (_param) { + case ACCOUNT_PARAM_CURRENCY_DIGITS: + // The number of decimal places in the account currency (int). + ConvertBasic::Convert(_value, currency_digits); + return; + case ACCOUNT_PARAM_FIFO_CLOSE: + // An indication showing that positions can only be closed by FIFO rule (bool). + ConvertBasic::Convert(_value, fifo_close); + return; + case ACCOUNT_PARAM_LEVERAGE: + // Account leverage (long). + ConvertBasic::Convert(_value, leverage); + return; + case ACCOUNT_PARAM_LIMIT_ORDERS: + // Maximum allowed number of active pending orders (int). + ConvertBasic::Convert(_value, limit_orders); + return; + case ACCOUNT_PARAM_LOGIN: + // Account number (long). + ConvertBasic::Convert(_value, login); + return; + case ACCOUNT_PARAM_MARGIN_MODE: + // Margin calculation mode (ENUM_ACCOUNT_MARGIN_MODE). + ConvertBasic::Convert(_value, margin_mode); + return; + case ACCOUNT_PARAM_MARGIN_SO_MODE: + // Mode for setting the minimal allowed margin (ENUM_ACCOUNT_STOPOUT_MODE). + ConvertBasic::Convert(_value, margin_so_mode); + return; + case ACCOUNT_PARAM_TRADE_ALLOWED: + // Allowed trade for the current account (bool). + ConvertBasic::Convert(_value, trade_allowed); + return; + case ACCOUNT_PARAM_TRADE_EXPERT: + // Allowed trade for an Expert Advisor (bool). + ConvertBasic::Convert(_value, trade_expert); + return; + case ACCOUNT_PARAM_TRADE_MODE: + // Account trade mode (ENUM_ACCOUNT_TRADE_MODE). + ConvertBasic::Convert(_value, trade_mode); + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } + // Serializers. + void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} + SerializerNodeType Serialize(Serializer& _s) { + _s.Pass(THIS_REF, "company", company); + _s.Pass(THIS_REF, "currency", currency); + _s.Pass(THIS_REF, "currency_digits", currency_digits); + _s.Pass(THIS_REF, "fifo_close", fifo_close); + _s.Pass(THIS_REF, "leverage", leverage); + _s.Pass(THIS_REF, "limit_orders", limit_orders); + _s.Pass(THIS_REF, "login", login); + _s.Pass(THIS_REF, "name", name); + _s.Pass(THIS_REF, "server", server); + _s.Pass(THIS_REF, "trade_allowed", trade_allowed); // Convert to states. + _s.Pass(THIS_REF, "trade_expert", trade_expert); // Convert to states. + _s.PassEnum(THIS_REF, "margin_mode", margin_mode); + _s.PassEnum(THIS_REF, "margin_so_mode", margin_so_mode); + _s.PassEnum(THIS_REF, "trade_mode", trade_mode); + return SerializerNodeObject; + } +}; diff --git a/Exchange/Account/AccountBase.h b/Exchange/Account/AccountBase.h index a2011f01f..6b8382c2a 100644 --- a/Exchange/Account/AccountBase.h +++ b/Exchange/Account/AccountBase.h @@ -21,12 +21,14 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. #include "../../Refs.mqh" +#include "../../Serializer/SerializerConverter.h" +#include "../../Serializer/SerializerJson.h" #include "AccountBase.struct.h" /** @@ -57,45 +59,59 @@ class AccountBase : public Dynamic { */ ~AccountBase() {} + /* Printer methods */ + + /** + * Returns textual representation of the object instance. + */ + const string ToString() override { return SerializerConverter::FromObject(THIS_REF).ToString(); } + + /* Serializers */ + + /** + * Returns serialized representation of the object instance. + */ + virtual SerializerNodeType Serialize(Serializer &_s) = 0; + /* Virtual methods */ /** * Returns balance value of the current account. */ - virtual datetime GetDateTime() { return TimeCurrent(); }; + virtual datetime GetDateTime() const { return TimeCurrent(); }; /** * Returns balance value of the current account. */ - virtual float GetBalance() = 0; + virtual float GetBalance() const = 0; /** * Returns credit value of the current account. */ - virtual float GetCredit() = 0; + virtual float GetCredit() const = 0; /** * Returns profit value of the current account. */ - virtual float GetProfit() = 0; + virtual float GetProfit() const = 0; /** * Returns equity value of the current account. */ - virtual float GetEquity() = 0; + virtual float GetEquity() const = 0; /** * Returns margin value of the current account. */ - virtual float GetMarginUsed() = 0; + virtual float GetMarginUsed() const = 0; /** * Returns free margin value of the current account. */ - virtual float GetMarginFree() = 0; + virtual float GetMarginFree() const = 0; /** * Get account available margin. */ - virtual float GetMarginAvail() = 0; + virtual float GetMarginAvail() const = 0; }; diff --git a/Exchange/Account/AccountBase.struct.h b/Exchange/Account/AccountBase.struct.h index d94d14f10..423784c2e 100644 --- a/Exchange/Account/AccountBase.struct.h +++ b/Exchange/Account/AccountBase.struct.h @@ -34,23 +34,16 @@ class Serializer; // Includes. -#include "Account.enum.h" -#include "../../Serializer/Serializer.h" +#include "../../Platform/Terminal.define.h" #include "../../Serializer/Serializer.enum.h" +#include "../../Serializer/Serializer.h" #include "../../Std.h" -#include "../../Platform/Terminal.define.h" +#include "Account.enum.h" // Struct for account entries. struct AccountBaseEntry { datetime dtime; double balance; - // Serializers. - void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} - SerializerNodeType Serialize(Serializer& _s) { - _s.Pass(THIS_REF, "time", dtime, SERIALIZER_FIELD_FLAG_DYNAMIC); - _s.Pass(THIS_REF, "balance", balance, SERIALIZER_FIELD_FLAG_DYNAMIC); - return SerializerNodeObject; - } /* Getters */ double Get(ENUM_ACCOUNT_INFO_DOUBLE _param) { switch (_param) { @@ -63,10 +56,23 @@ struct AccountBaseEntry { SetUserError(ERR_INVALID_PARAMETER); return WRONG_VALUE; } + // Serializers. + SERIALIZER_EMPTY_STUB; + SerializerNodeType Serialize(Serializer& _s) { + _s.Pass(THIS_REF, "time", dtime, SERIALIZER_FIELD_FLAG_DYNAMIC); + _s.Pass(THIS_REF, "balance", balance, SERIALIZER_FIELD_FLAG_DYNAMIC); + return SerializerNodeObject; + } }; // Struct for account base. struct AccountBaseState { datetime last_updated; double balance; + // Serializers. + SERIALIZER_EMPTY_STUB; + SerializerNodeType Serialize(Serializer& _s) { + _s.Pass(THIS_REF, "balance", balance); + return SerializerNodeObject; + } }; diff --git a/Exchange/Account/AccountForex.h b/Exchange/Account/AccountForex.h index ad7a97722..3a9001e54 100644 --- a/Exchange/Account/AccountForex.h +++ b/Exchange/Account/AccountForex.h @@ -35,7 +35,6 @@ */ class AccountForex : public Account { protected: - // AP AccountParams; /** * Init code (called on constructor). */ @@ -49,8 +48,65 @@ class AccountForex : public Account { */ AccountForex() { Init(); } + /** + * Class constructor with account params. + */ + AccountForex(AccountParams &_aparams) : Account(_aparams) { Init(); } + /** * Class deconstructor. */ ~AccountForex() {} + + + /* Implementation of virtual methods */ + + /** + * Returns balance value of the current account. + */ + float GetBalance() const { + return 0.0f; + } + + /** + * Returns credit value of the current account. + */ + float GetCredit() const { + return 0.0f; + } + + /** + * Returns profit value of the current account. + */ + float GetProfit() const { + return 0.0f; + } + + /** + * Returns equity value of the current account. + */ + float GetEquity() const { + return 0.0f; + } + + /** + * Returns margin value of the current account. + */ + float GetMarginUsed() const { + return 0.0f; + } + + /** + * Returns free margin value of the current account. + */ + float GetMarginFree() const { + return 0.0f; + } + + /** + * Get account available margin. + */ + float GetMarginAvail() const { + return 0.0f; + } }; diff --git a/Exchange/Account/AccountForex.struct.h b/Exchange/Account/AccountForex.struct.h index 34abc2abc..1c8062c7f 100644 --- a/Exchange/Account/AccountForex.struct.h +++ b/Exchange/Account/AccountForex.struct.h @@ -34,9 +34,9 @@ class Serializer; // Includes. -#include "../../Serializer/Serializer.h" -#include "../../Serializer/Serializer.enum.h" #include "../../Platform/Terminal.define.h" +#include "../../Serializer/Serializer.enum.h" +#include "../../Serializer/Serializer.h" // Struct for account entries. struct AccountForexEntry : public AccountBaseEntry { @@ -99,4 +99,14 @@ struct AccountForexState : public AccountBaseState { double margin_used; double margin_free; double margin_avail; + // Serializers. + SerializerNodeType Serialize(Serializer& s) { + s.Pass(THIS_REF, "credit", credit); + s.Pass(THIS_REF, "equity", equity); + s.Pass(THIS_REF, "profit", profit); + s.Pass(THIS_REF, "margin_used", margin_used); + s.Pass(THIS_REF, "margin_free", margin_free); + s.Pass(THIS_REF, "margin_avail", margin_avail); + return SerializerNodeObject; + } }; diff --git a/Exchange/Account/AccountMt.h b/Exchange/Account/AccountMt.h index e21e936aa..19b957e7f 100644 --- a/Exchange/Account/AccountMt.h +++ b/Exchange/Account/AccountMt.h @@ -84,16 +84,16 @@ class AccountMt : public AccountBase { * @return * Returns account entry. */ - AccountEntry GetEntry() { + AccountEntry GetEntry() const { AccountEntry _entry; - _entry.dtime = TimeCurrent(); - _entry.balance = GetBalance(); - _entry.credit = GetCredit(); - _entry.equity = GetEquity(); - _entry.profit = GetProfit(); - _entry.margin_used = GetMarginUsed(); - _entry.margin_free = GetMarginFree(); - _entry.margin_avail = GetMarginAvail(); + _entry.dtime = AccountMt::GetDateTime(); + _entry.balance = AccountMt::GetBalance(); + _entry.credit = AccountMt::GetCredit(); + _entry.equity = AccountMt::GetEquity(); + _entry.profit = AccountMt::GetProfit(); + _entry.margin_used = AccountMt::GetMarginUsed(); + _entry.margin_free = AccountMt::GetMarginFree(); + _entry.margin_avail = AccountMt::GetMarginAvail(); return _entry; } @@ -112,7 +112,7 @@ class AccountMt : public AccountBase { * Returns the current account name. */ static string AccountName() { return AccountInfoString(ACCOUNT_NAME); } - string GetAccountName() { return AccountName(); } + string GetAccountName() const { return AccountName(); } /** * Returns the connected server name. @@ -124,13 +124,13 @@ class AccountMt : public AccountBase { * Returns currency name of the current account. */ static string AccountCurrency() { return AccountInfoString(ACCOUNT_CURRENCY); } - string GetCurrency() { return AccountCurrency(); } + string GetCurrency() const { return AccountCurrency(); } /** * Returns the brokerage company name where the current account was registered. */ static string AccountCompany() { return AccountInfoString(ACCOUNT_COMPANY); } - string GetCompanyName() { return AccountCompany(); } + string GetCompanyName() const { return AccountCompany(); } /* Double getters */ @@ -138,7 +138,7 @@ class AccountMt : public AccountBase { * Returns balance value of the current account. */ static double AccountBalance() { return AccountInfoDouble(ACCOUNT_BALANCE); } - float GetBalance() override { + float GetBalance() const override { // @todo: Adds caching. // return UpdateStats(ACC_BALANCE, AccountBalance()); return (float)AccountMt::AccountBalance(); @@ -148,7 +148,7 @@ class AccountMt : public AccountBase { * Returns credit value of the current account. */ static double AccountCredit() { return AccountInfoDouble(ACCOUNT_CREDIT); } - float GetCredit() override { + float GetCredit() const override { // @todo: Adds caching. // return UpdateStats(ACC_CREDIT, AccountCredit()); return (float)AccountMt::AccountCredit(); @@ -158,7 +158,7 @@ class AccountMt : public AccountBase { * Returns profit value of the current account. */ static double AccountProfit() { return AccountInfoDouble(ACCOUNT_PROFIT); } - float GetProfit() override { + float GetProfit() const override { // @todo: Adds caching. // return UpdateStats(ACC_PROFIT, AccountProfit()); return (float)AccountMt::AccountProfit(); @@ -168,7 +168,7 @@ class AccountMt : public AccountBase { * Returns equity value of the current account. */ static double AccountEquity() { return AccountInfoDouble(ACCOUNT_EQUITY); } - float GetEquity() override { + float GetEquity() const override { // @todo: Adds caching. // return UpdateStats(ACC_EQUITY, AccountEquity()); return (float)AccountMt::AccountEquity(); @@ -178,7 +178,7 @@ class AccountMt : public AccountBase { * Returns margin value of the current account. */ static double AccountMargin() { return AccountInfoDouble(ACCOUNT_MARGIN); } - float GetMarginUsed() { + float GetMarginUsed() const override { // @todo: Adds caching. // return UpdateStats(ACC_MARGIN_USED, AccountMargin()); return (float)AccountMt::AccountMargin(); @@ -200,7 +200,7 @@ class AccountMt : public AccountBase { * Returns free margin value of the current account. */ static double AccountFreeMargin() { return AccountInfoDouble(ACCOUNT_MARGIN_FREE); } - float GetMarginFree() override { + float GetMarginFree() const override { // @todo: Adds caching. // return UpdateStats(ACC_MARGIN_FREE, AccountFreeMargin()); return (float)AccountMt::AccountFreeMargin(); @@ -212,7 +212,7 @@ class AccountMt : public AccountBase { * @return * Account's free margin in percentage. */ - double GetMarginFreeInPct() { + double GetMarginFreeInPct() const { double _margin_free = GetMarginFree(); double _margin_avail = GetMarginAvail(); return _margin_avail > 0 ? 100 / _margin_avail * _margin_free : 0; @@ -222,19 +222,19 @@ class AccountMt : public AccountBase { * Returns the current account number. */ static int64 AccountNumber() { return AccountInfoInteger(ACCOUNT_LOGIN); } - int64 GetLogin() { return AccountNumber(); } + int64 GetLogin() const { return AccountNumber(); } /** * Returns leverage of the current account. */ static int64 AccountLeverage() { return AccountInfoInteger(ACCOUNT_LEVERAGE); } - int64 GetLeverage() { return AccountLeverage(); } + int64 GetLeverage() const { return AccountLeverage(); } /** * Returns the calculation mode for the Stop Out level. */ static int AccountStopoutMode() { return (int)AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE); } - int GetStopoutMode() { return AccountStopoutMode(); } + int GetStopoutMode() const { return AccountStopoutMode(); } /** * Returns the value of the Stop Out level. @@ -243,7 +243,7 @@ class AccountMt : public AccountBase { * is expressed in percents or in the deposit currency. */ static double AccountStopoutLevel() { return AccountInfoDouble(ACCOUNT_MARGIN_SO_SO); } - double GetStopoutLevel() { return AccountStopoutLevel(); } + double GetStopoutLevel() const { return AccountStopoutLevel(); } /** * Get a maximum allowed number of active pending orders set by broker. @@ -252,7 +252,7 @@ class AccountMt : public AccountBase { * Returns the limit orders (0 for unlimited). */ static int64 AccountLimitOrders() { return AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); } - int64 GetLimitOrders(unsigned int _max = 999) { + int64 GetLimitOrders(unsigned int _max = 999) const { int64 _limit = AccountLimitOrders(); return _limit > 0 ? _limit : _max; } @@ -263,13 +263,13 @@ class AccountMt : public AccountBase { * Get account total balance (including credit). */ static double AccountTotalBalance() { return AccountBalance() + AccountCredit(); } - float GetTotalBalance() { return (float)(GetBalance() + GetCredit()); } + float GetTotalBalance() const { return (float)(GetBalance() + GetCredit()); } /** * Get account available margin. */ static double AccountAvailMargin() { return fmin(AccountFreeMargin(), AccountTotalBalance()); } - float GetMarginAvail() override { return (float)AccountAvailMargin(); } + float GetMarginAvail() const override { return (float)AccountAvailMargin(); } /** * Returns the calculation mode of free margin allowed to open orders on the current account. @@ -324,17 +324,17 @@ class AccountMt : public AccountBase { /** * Get account init balance. */ - double GetInitBalance() { return init_balance; } + double GetInitBalance() const { return init_balance; } /** * Get account start balance. */ - double GetStartBalance() { return start_balance; } + double GetStartBalance() const { return start_balance; } /** * Get account init credit. */ - double GetStartCredit() { return start_credit; } + double GetStartCredit() const { return start_credit; } /* Calculation methods */ @@ -388,7 +388,7 @@ class AccountMt : public AccountBase { : -1); #endif } - double GetAccountFreeMarginCheck(ENUM_ORDER_TYPE _cmd, double _volume) { + double GetAccountFreeMarginCheck(ENUM_ORDER_TYPE _cmd, double _volume) const { return AccountFreeMarginCheck(_Symbol, _cmd, _volume); } @@ -616,7 +616,7 @@ class AccountMt : public AccountBase { /** * Returns text info about the account. */ - string const ToString() { + string const ToString() override { return StringFormat( "Type: %s, Server/Company/Name: %s/%s/%s, Currency: %s, Balance: %g, Credit: %g, Equity: %g, Profit: %g, " "Margin Used/Free/Avail: %g(%.1f%%)/%g/%g, Orders limit: %g: Leverage: 1:%d, StopOut Level: %d (Mode: %d)", @@ -639,7 +639,7 @@ class AccountMt : public AccountBase { /** * Returns serialized representation of the object instance. */ - SerializerNodeType Serialize(Serializer &_s) { + SerializerNodeType Serialize(Serializer &_s) override { AccountEntry _entry = GetEntry(); _s.PassStruct(THIS_REF, "account-entry", _entry, SERIALIZER_FIELD_FLAG_DYNAMIC); return SerializerNodeObject; diff --git a/Exchange/Account/tests/Account.test.mq5 b/Exchange/Account/tests/Account.test.mq5 index a50189202..2279f14ba 100644 --- a/Exchange/Account/tests/Account.test.mq5 +++ b/Exchange/Account/tests/Account.test.mq5 @@ -71,7 +71,7 @@ class AccountTest : public Account { */ int OnInit() { bool _result = true; - AccountTest acc1; + // AccountTest acc1; // ... return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } diff --git a/Exchange/Account/tests/AccountForex.test.mq5 b/Exchange/Account/tests/AccountForex.test.mq5 index ec66bc39e..c751832a7 100644 --- a/Exchange/Account/tests/AccountForex.test.mq5 +++ b/Exchange/Account/tests/AccountForex.test.mq5 @@ -71,7 +71,7 @@ class AccountForexTest : public Account { */ int OnInit() { bool _result = true; - AccountForexTest acc1; + // AccountForexTest acc1; // ... return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } diff --git a/Exchange/Account/tests/Makefile b/Exchange/Account/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Exchange/Account/tests/Makefile +++ b/Exchange/Account/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Exchange/Exchange.enum.h b/Exchange/Exchange.enum.h new file mode 100644 index 000000000..3159069f6 --- /dev/null +++ b/Exchange/Exchange.enum.h @@ -0,0 +1,44 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes Exchange's enumerations. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Exchange actions. +enum ENUM_EXCHANGE_ACTION { + EXCHANGE_ACTION_ADD_ACCOUNT = 1, // Add Account + EXCHANGE_ACTION_ADD_SYMBOL, // Add Symbol + FINAL_ENUM_EXCHANGE_ACTION_ENTRY +}; + +// Exchange conditions. +enum ENUM_EXCHANGE_CONDITION { + EXCHANGE_COND_IS_ACTIVE = 1, // Is active + FINAL_ENUM_EXCHANGE_CONDITION_ENTRY +}; diff --git a/Exchange/Exchange.h b/Exchange/Exchange.h index 54c70277c..bb1ddf0f7 100644 --- a/Exchange/Exchange.h +++ b/Exchange/Exchange.h @@ -21,23 +21,29 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. #include "../Exchange/SymbolInfo/SymbolInfo.h" +#include "../Serializer/Serializer.h" #include "../Storage/Dict/DictObject.h" +#include "../Storage/State.struct.h" +#include "../Task/TaskManager.h" +#include "../Task/Taskable.h" #include "../Trade.mqh" -#include "Account/Account.h" +#include "Account/AccountForex.h" +#include "Exchange.enum.h" #include "Exchange.struct.h" -class Exchange : public Dynamic { +class Exchange : public Taskable { protected: - DictStruct> accounts; + DictStruct> accounts; DictStruct> symbols; DictStruct> trades; ExchangeParams eparams; + State estate; public: /** @@ -60,9 +66,17 @@ class Exchange : public Dynamic { /** * Adds account instance to the list. */ - void AccountAdd(AccountBase *_account, string _name) { + void AccountAdd(AccountBase *_account, int _id = 0) { Ref _ref = _account; - accounts.Set(_name, _ref); + accounts.Set(_id, _ref); + } + + /** + * Adds account instance to the list. + */ + void AccountAdd(AccountParams &_aparams) { + AccountBase *_account = new AccountForex(_aparams); + AccountAdd(_account); } /** @@ -81,12 +95,24 @@ class Exchange : public Dynamic { trades.Set(_name, _ref); } + /* Getters */ + + /** + * Gets DictStruct reference to accounts. + */ + DictStruct> *GetAccounts() { return GetPointer(accounts); } + + /** + * Gets DictStruct reference to symbols. + */ + DictStruct> *GetSymbols() { return GetPointer(symbols); } + /* Removers */ /** * Removes account instance from the list. */ - void AccountRemove(string _name) { accounts.Unset(_name); } + void AccountRemove(int _id) { accounts.Unset(_id); } /** * Removes symbol instance from the list. @@ -97,4 +123,84 @@ class Exchange : public Dynamic { * Removes trade instance from the list. */ void TradeRemove(string _name) { trades.Unset(_name); } + + /* Taskable methods */ + + /** + * Checks a condition. + */ + bool Check(const TaskConditionEntry &_entry) override { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + SetUserError(ERR_INVALID_PARAMETER); + } + return _result; + } + + /** + * Gets a data param entry. + */ + DataParamEntry Get(const TaskGetterEntry &_entry) override { + DataParamEntry _result; + switch (_entry.GetId()) { + default: + SetUserError(ERR_INVALID_PARAMETER); + } + return _result; + } + + /** + * Runs an action. + */ + bool Run(const TaskActionEntry &_entry) override { + bool _result = true; + switch (_entry.GetId()) { + case EXCHANGE_ACTION_ADD_ACCOUNT: + if (!_entry.HasArgs()) { + AccountAdd(new AccountForex()); + } else { + AccountParams _aparams(_entry.GetArg(0).ToString()); + Ref _account1_ref = new AccountForex(_aparams); + accounts.Set(_aparams.Get(ACCOUNT_PARAM_LOGIN), _account1_ref); + } + break; + default: + _result = false; + SetUserError(ERR_INVALID_PARAMETER); + } + return _result; + } + + /** + * Sets an entry value. + */ + bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) override { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + SetUserError(ERR_INVALID_PARAMETER); + } + return _result; + } + + /* Serializers */ + + /** + * Returns serialized representation of the object instance. + */ + SerializerNodeType Serialize(Serializer &_s) { + _s.PassStruct(THIS_REF, "eparams", eparams); + _s.PassStruct(THIS_REF, "accounts", accounts); + //_s.PassStruct(THIS_REF, "symbols", symbols); + //_s.PassStruct(THIS_REF, "trades", trades); + return SerializerNodeObject; + } + + /** + * Returns textual representation of the object instance. + */ + const string ToString() override { return SerializerConverter::FromObject(THIS_REF).ToString(); } }; diff --git a/Exchange/Exchange.struct.h b/Exchange/Exchange.struct.h index 13c9c569b..1bba7a371 100644 --- a/Exchange/Exchange.struct.h +++ b/Exchange/Exchange.struct.h @@ -26,17 +26,69 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -// Forward class declaration. -class Exchange; +// Includes. +#include "../Serializer/SerializerNode.enum.h" /* Defines struct for Exchange parameters. */ struct ExchangeParams { + private: + int id; + string name; + + public: + // Enumeration of exchange parameters. + enum ENUM_EXCHANGE_PARAM { + EXCHANGE_PARAM_ID = 1, // ID + EXCHANGE_PARAM_NAME, // Name + FINAL_ENUM_EXCHANGE_PARAM_ENTRY + }; +#define ENUM_EXCHANGE_PARAM STRUCT_ENUM(ExchangeParams, ENUM_EXCHANGE_PARAM) + public: // Constructors. - ExchangeParams() {} - ExchangeParams(const ExchangeParams &_eparams) {} - int64 id; + ExchangeParams(int _id = 0, string _name = "") : id(_id), name(_name) {} + ExchangeParams(const ExchangeParams &_eparams) { THIS_REF = _eparams; } + ExchangeParams(string _entry) { SerializerConverter::FromString(_entry).ToStruct(THIS_REF); } + // Getters. + template + T Get(ENUM_EXCHANGE_PARAM _param) { + T _out; + switch (_param) { + case EXCHANGE_PARAM_ID: + return (T)id; + case EXCHANGE_PARAM_NAME: + ConvertBasic::Convert(name, _out); + return _out; + default: + Alert("Unsupported param: ", EnumToString(_param)); + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + // Setters. + template + void Set(ENUM_EXCHANGE_PARAM _param, T _value) { + switch (_param) { + case EXCHANGE_PARAM_ID: + ConvertBasic::Convert(_value, id); + break; + case EXCHANGE_PARAM_NAME: + ConvertBasic::Convert(_value, name); + break; + default: + Alert("Unsupported param: ", EnumToString(_param)); + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } + // Serializers. + SerializerNodeType Serialize(Serializer &s) { + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "name", name); + return SerializerNodeObject; + } }; diff --git a/Exchange/README.md b/Exchange/README.md index 31411ab33..bb2cda512 100644 --- a/Exchange/README.md +++ b/Exchange/README.md @@ -4,7 +4,7 @@ ```mermaid classDiagram - Dynamic <|-- Exchange + Taskable <|-- Exchange Exchange: Account[] Exchange: Symbol[] Exchange: Trade[] diff --git a/Exchange/SymbolInfo/SymbolInfo.extern.h b/Exchange/SymbolInfo/SymbolInfo.extern.h index 98a2f4a7c..ca74989b4 100644 --- a/Exchange/SymbolInfo/SymbolInfo.extern.h +++ b/Exchange/SymbolInfo/SymbolInfo.extern.h @@ -32,10 +32,21 @@ // Define external global functions. #ifndef __MQL__ -extern int64 SymbolInfoInteger(string name, ENUM_SYMBOL_INFO_INTEGER prop_id); -extern bool SymbolInfoMarginRate(string name, ENUM_ORDER_TYPE order_type, double &initial_margin_rate, - double &maintenance_margin_rate); -extern bool SymbolInfoTick(string symbol, MqlTick &tick); +int64 SymbolInfoInteger(string name, ENUM_SYMBOL_INFO_INTEGER prop_id) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} + +bool SymbolInfoMarginRate(string name, ENUM_ORDER_TYPE order_type, double& initial_margin_rate, + double& maintenance_margin_rate) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return false; +} + +bool SymbolInfoTick(string symbol, MqlTick& tick) { + Print("Not yet implemented: ", __FUNCTION__, " returns false."); + return 0; +} // Define external global variables. class SymbolGetter { diff --git a/Exchange/SymbolInfo/tests/Makefile b/Exchange/SymbolInfo/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Exchange/SymbolInfo/tests/Makefile +++ b/Exchange/SymbolInfo/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Exchange/tests/Exchange.test.mq5 b/Exchange/tests/Exchange.test.mq5 index 5d94b2246..52cdfdd96 100644 --- a/Exchange/tests/Exchange.test.mq5 +++ b/Exchange/tests/Exchange.test.mq5 @@ -24,6 +24,9 @@ * Test functionality of Exchange class. */ +// Defines. +#define __debug_serializer__ + // Includes. #include "../../Platform/Platform.h" #include "../../Test.mqh" @@ -34,40 +37,58 @@ class AccountDummy : public AccountBase { /** * Returns balance value of the current account. */ - float GetBalance() { return 0; } + float GetBalance() const { return 0; } /** * Returns credit value of the current account. */ - float GetCredit() { return 0; } + float GetCredit() const { return 0; } /** * Returns profit value of the current account. */ - float GetProfit() { return 0; } + float GetProfit() const { return 0; } /** * Returns equity value of the current account. */ - float GetEquity() { return 0; } + float GetEquity() const { return 0; } /** * Returns margin value of the current account. */ - float GetMarginUsed() { return 0; } + float GetMarginUsed() const { return 0; } /** * Returns free margin value of the current account. */ - float GetMarginFree() { return 0; } + float GetMarginFree() const { return 0; } /** * Get account available margin. */ - float GetMarginAvail() { return 0; } + float GetMarginAvail() const { return 0; } + + /* Serializers */ + + /** + * Returns serialized representation of the object instance. + */ + virtual SerializerNodeType Serialize(Serializer &_s) { return SerializerNodeObject; } }; -class ExchangeDummy : public Exchange {}; +class ExchangeDummy : public Exchange { + public: + /** + * Class constructor without parameters. + */ + ExchangeDummy(){}; + + /** + * Class constructor with parameters. + */ + ExchangeDummy(ExchangeParams &_eparams) { eparams = _eparams; }; +}; class SymbolDummy : public SymbolInfo {}; class TradeDummy : public Trade { public: @@ -86,8 +107,8 @@ bool TestExchange01() { // Attach instances of dummy accounts. Ref account01 = new AccountDummy(); Ref account02 = new AccountDummy(); - exchange REF_DEREF AccountAdd(account01.Ptr(), "Account01"); - exchange REF_DEREF AccountAdd(account02.Ptr(), "Account02"); + exchange REF_DEREF AccountAdd(account01.Ptr(), 0); + exchange REF_DEREF AccountAdd(account02.Ptr(), 1); // Attach instances of dummy symbols. Ref symbol01 = new SymbolDummy(); @@ -104,6 +125,24 @@ bool TestExchange01() { return _result; } +// Test dummy Exchange via tasks. +bool TestExchange02() { + bool _result = true; + // Initialize a dummy Exchange instance. + ExchangeParams _eparams(0, __FUNCTION__); + Ref exchange = new ExchangeDummy(_eparams); + // Add account01 via task. + TaskActionEntry _task_add_acc_01(EXCHANGE_ACTION_ADD_ACCOUNT); + exchange.Ptr().Run(_task_add_acc_01); + // Add account02 via task from JSON. + TaskActionEntry _task_add_acc_02(EXCHANGE_ACTION_ADD_ACCOUNT); + DataParamEntry _acc_02_entry = "{\"id\": 1, \"name\": \"Account02\", \"currency\": \"USD\"}"; + _task_add_acc_02.ArgAdd(_acc_02_entry); + exchange.Ptr().Run(_task_add_acc_02); + Print(exchange.Ptr().ToString()); + return _result; +} + /** * Implements OnInit(). */ @@ -111,5 +150,6 @@ int OnInit() { Platform::Init(); bool _result = true; assertTrueOrFail(TestExchange01(), "Fail!"); + assertTrueOrFail(TestExchange02(), "Fail!"); return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } diff --git a/Exchange/tests/Makefile b/Exchange/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Exchange/tests/Makefile +++ b/Exchange/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/File.mqh b/File.mqh index 2342032de..4edc59dcb 100644 --- a/File.mqh +++ b/File.mqh @@ -116,7 +116,7 @@ class File { static bool SaveFile(string path, string data, bool binary = false) { ResetLastError(); - int handle = FileOpen(path, FILE_WRITE | (binary ? FILE_BIN : FILE_ANSI)); + int handle = FileOpen(path, FILE_WRITE | (binary ? FILE_BIN : FILE_TXT), "", CP_UTF8); if (handle == INVALID_HANDLE) { string terminalDataPath = TerminalInfoString(TERMINAL_DATA_PATH); @@ -131,7 +131,14 @@ class File { return false; } - FileWriteString(handle, data); + if (binary) { + uchar buffer[]; + StringToCharArray(data, buffer, 0, WHOLE_ARRAY, CP_UTF8); + FileWriteArray(handle, buffer, 0, ArraySize(buffer)); + } + else { + FileWriteString(handle, data); + } FileClose(handle); diff --git a/Indicator/Indicator.h b/Indicator/Indicator.h index fb8859785..795fd7e74 100644 --- a/Indicator/Indicator.h +++ b/Indicator/Indicator.h @@ -32,11 +32,13 @@ struct IndicatorParams; #include "Indicator.enum.h" #include "Indicator.struct.h" #include "Indicator.struct.serialize.h" +#include "IndicatorCandle.enum.h" #include "IndicatorData.h" // Includes. #include "../Indicators/DrawIndicator.mqh" #include "../Math/Math.h" +#include "../Platform/Chart/Chart.define.h" #include "../Refs.mqh" #include "../Serializer/Serializer.h" #include "../Serializer/SerializerCsv.h" @@ -160,15 +162,20 @@ class Indicator : public IndicatorData { /** * Returns the highest bar's index (shift). */ - template - int GetHighest(int count = WHOLE_ARRAY, int start_bar = 0) { + int GetHighest(int mode, int count = WHOLE_ARRAY, int start_bar = 0) override { + if (GetCandle() != THIS_PTR) { + Alert("You can only use ", __FUNCTION__, " on the Candle-based indicator! ", GetFullName(), + " is not a Candle indicator."); + DebugBreak(); + return -1; + } + int max_idx = -1; double max = -DBL_MAX; int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); for (int shift = start_bar; shift <= last_bar; ++shift) { - IndicatorDataEntry _entry = GetEntry(shift); - double value = _entry.GetMax(GetModeCount()); + double value = GetValue((int)GetCandleIndicatorMode(mode), shift); if (value > max) { max = value; max_idx = shift; @@ -181,15 +188,20 @@ class Indicator : public IndicatorData { /** * Returns the lowest bar's index (shift). */ - template - int GetLowest(int count = WHOLE_ARRAY, int start_bar = 0) { + int GetLowest(int mode, int count = WHOLE_ARRAY, int start_bar = 0) override { + if (GetCandle() != THIS_PTR) { + Alert("You can only use ", __FUNCTION__, " on the Candle-based indicator! ", GetFullName(), + " is not a Candle indicator."); + DebugBreak(); + return -1; + } + int min_idx = -1; double min = DBL_MAX; int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); for (int shift = start_bar; shift <= last_bar; ++shift) { - IndicatorDataEntry _entry = GetEntry(shift); - double value = _entry.GetMin(GetModeCount()); + double value = GetValue((int)GetCandleIndicatorMode(mode), shift); if (value < min) { min = value; min_idx = shift; @@ -199,6 +211,35 @@ class Indicator : public IndicatorData { return min_idx; } + /** + * Converts Series Array Indentifier into mode index to be retrieved from Candle indicator. + * + * Possible values: + * MODE_OPEN, MODE_LOW, MODE_HIGH, MODE_CLOSE, MODE_VOLUME, MODE_TIME. + */ + ENUM_INDI_CANDLE_MODE GetCandleIndicatorMode(int _series_array_id) { + switch (_series_array_id) { + case MODE_OPEN: + return INDI_CANDLE_MODE_PRICE_OPEN; + case MODE_LOW: + return INDI_CANDLE_MODE_PRICE_LOW; + case MODE_HIGH: + return INDI_CANDLE_MODE_PRICE_HIGH; + case MODE_CLOSE: + return INDI_CANDLE_MODE_PRICE_CLOSE; + case MODE_VOLUME: + case MODE_REAL_VOLUME: + return INDI_CANDLE_MODE_VOLUME; + case MODE_TIME: + return INDI_CANDLE_MODE_TIME; + default: + Alert("Unsupported mode ", IntegerToString(_series_array_id), ", for ", __FUNCTION__, ""); + DebugBreak(); + } + + return (ENUM_INDI_CANDLE_MODE)0; + } + /* Setters */ /** diff --git a/Indicator/Indicator.struct.h b/Indicator/Indicator.struct.h index c488930ce..4e26b636b 100644 --- a/Indicator/Indicator.struct.h +++ b/Indicator/Indicator.struct.h @@ -71,10 +71,10 @@ struct IndicatorParams { /* Special methods */ // Constructor. IndicatorParams(ENUM_INDICATOR_TYPE _itype = INDI_NONE, ENUM_TIMEFRAMES _tf = PERIOD_CURRENT, string _name = "") - : bps(0), - custom_indi_name(""), + : custom_indi_name(""), name(_name), shift(0), + bps(0), // max_modes(_max_modes), // max_buffers(10), // idstype(_idstype), @@ -84,7 +84,7 @@ struct IndicatorParams { itype(_itype) { Init(); }; - IndicatorParams(string _name) : bps(0), custom_indi_name(""), name(_name), shift(0) { Init(); }; + IndicatorParams(string _name) : custom_indi_name(""), name(_name), shift(0), bps(0) { Init(); }; /* Getters */ template T Get(STRUCT_ENUM(IndicatorParams, ENUM_INDI_PARAMS_PROP) _prop) const { diff --git a/Indicator/IndicatorBase.h b/Indicator/IndicatorBase.h index e15aaff42..a2bfbe26c 100644 --- a/Indicator/IndicatorBase.h +++ b/Indicator/IndicatorBase.h @@ -31,7 +31,7 @@ #endif // Includes. -#include "../Bar.struct.h" +#include "../Platform/Chart/Bar.struct.h" #include "../Log.mqh" #include "../Platform/Chart/Chart.struct.tf.h" #include "../Platform/Platform.extern.h" diff --git a/Indicator/IndicatorCandle.enum.h b/Indicator/IndicatorCandle.enum.h new file mode 100644 index 000000000..7a17aaf6f --- /dev/null +++ b/Indicator/IndicatorCandle.enum.h @@ -0,0 +1,48 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2024, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes IndicatorCandle's enums. + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +// Indicator modes. +enum ENUM_INDI_CANDLE_MODE { + INDI_CANDLE_MODE_PRICE_OPEN, + INDI_CANDLE_MODE_PRICE_HIGH, + INDI_CANDLE_MODE_PRICE_LOW, + INDI_CANDLE_MODE_PRICE_CLOSE, + INDI_CANDLE_MODE_SPREAD, + INDI_CANDLE_MODE_TICK_VOLUME, + INDI_CANDLE_MODE_TIME, + INDI_CANDLE_MODE_VOLUME, + FINAL_INDI_CANDLE_MODE_ENTRY, + // Following modes are dynamically calculated. + INDI_CANDLE_MODE_PRICE_MEDIAN, + INDI_CANDLE_MODE_PRICE_TYPICAL, + INDI_CANDLE_MODE_PRICE_WEIGHTED, +}; diff --git a/Indicator/IndicatorCandle.h b/Indicator/IndicatorCandle.h index c97d9a9d9..7124a3506 100644 --- a/Indicator/IndicatorCandle.h +++ b/Indicator/IndicatorCandle.h @@ -26,7 +26,7 @@ #endif // Includes. -#include "../Candle.struct.h" +#include "../Platform/Chart/Candle.struct.h" #include "../Storage/ItemsHistory.h" #include "../Storage/ValueStorage.price_median.h" #include "../Storage/ValueStorage.price_typical.h" @@ -36,6 +36,7 @@ #include "../Storage/ValueStorage.time.h" #include "../Storage/ValueStorage.volume.h" #include "Indicator.h" +#include "IndicatorCandle.enum.h" #include "IndicatorCandle.provider.h" #include "IndicatorData.h" #include "TickBarCounter.h" @@ -44,23 +45,6 @@ #define INDI_CANDLE_HISTORY_SIZE 86400 #endif -// Indicator modes. -enum ENUM_INDI_CANDLE_MODE { - INDI_CANDLE_MODE_PRICE_OPEN, - INDI_CANDLE_MODE_PRICE_HIGH, - INDI_CANDLE_MODE_PRICE_LOW, - INDI_CANDLE_MODE_PRICE_CLOSE, - INDI_CANDLE_MODE_SPREAD, - INDI_CANDLE_MODE_TICK_VOLUME, - INDI_CANDLE_MODE_TIME, - INDI_CANDLE_MODE_VOLUME, - FINAL_INDI_CANDLE_MODE_ENTRY, - // Following modes are dynamically calculated. - INDI_CANDLE_MODE_PRICE_MEDIAN, - INDI_CANDLE_MODE_PRICE_TYPICAL, - INDI_CANDLE_MODE_PRICE_WEIGHTED, -}; - /** * Class to deal with candle indicators. */ diff --git a/Indicator/IndicatorCandle.provider.h b/Indicator/IndicatorCandle.provider.h index 4eb894c06..d050a9ee0 100644 --- a/Indicator/IndicatorCandle.provider.h +++ b/Indicator/IndicatorCandle.provider.h @@ -30,7 +30,7 @@ #endif // Includes. -#include "../Candle.struct.h" +#include "../Platform/Chart/Candle.struct.h" #include "../Storage/ItemsHistory.h" /** diff --git a/Indicator/IndicatorData.h b/Indicator/IndicatorData.h index 181ce434f..3bf08dc2e 100644 --- a/Indicator/IndicatorData.h +++ b/Indicator/IndicatorData.h @@ -35,8 +35,8 @@ struct ExternInstantiateIndicatorBufferValueStorageDouble { }; // Includes. -#include "../Bar.struct.h" #include "../Exchange/SymbolInfo/SymbolInfo.struct.h" +#include "../Platform/Chart/Bar.struct.h" #include "../Platform/Chart/Chart.struct.tf.h" #include "../Storage/Cache/IndiBufferCache.h" #include "../Storage/Flags.struct.h" @@ -220,7 +220,7 @@ class IndicatorData : public IndicatorBase { /** * Get full name of the indicator (with "over ..." part). */ - string GetFullName() { + string GetFullName() override { int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); string _mode; @@ -408,13 +408,13 @@ class IndicatorData : public IndicatorBase { */ template double GetMax(int start_bar = 0, int count = WHOLE_ARRAY) { - double max = NULL; + double max = -DBL_MAX; int last_bar = count == WHOLE_ARRAY ? (int)(GetBarShift(GetLastBarTime())) : (start_bar + count - 1); int _max_modes = Get(STRUCT_ENUM(IndicatorDataParams, IDATA_PARAM_MAX_MODES)); for (int shift = start_bar; shift <= last_bar; ++shift) { double value = GetEntry(shift).GetMax(_max_modes); - if (max == NULL || value > max) { + if (max == -DBL_MAX || value > max) { max = value; } } @@ -619,7 +619,7 @@ class IndicatorData : public IndicatorBase { Ref _source = FetchDataSource((ENUM_INDICATOR_TYPE)_source_id); if (!_source.IsSet()) { - Alert(GetName(), " has no built-in source indicator ", _source_id); + Alert(GetFullName(), " has no built-in source indicator ", _source_id); DebugBreak(); } else { indicators.Set(_source_id, _source); @@ -1158,22 +1158,54 @@ class IndicatorData : public IndicatorBase { /** * Gets ask price for a given shift. Return current ask price if _shift wasn't passed or is 0. */ - virtual double GetAsk(int _shift = 0) { return GetTick() PTR_DEREF GetAsk(_shift); } + virtual double GetAsk(int _shift = 0) { + if (GetTick() == THIS_PTR) { + Alert(GetFullName(), " tick indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetTick() PTR_DEREF GetAsk(_shift); + } /** * Gets bid price for a given shift. Return current bid price if _shift wasn't passed or is 0. */ - virtual double GetBid(int _shift = 0) { return GetTick() PTR_DEREF GetBid(_shift); } + virtual double GetBid(int _shift = 0) { + if (GetTick() == THIS_PTR) { + Alert(GetFullName(), " tick indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetTick() PTR_DEREF GetBid(_shift); + } /** * Returns the number of bars on the chart decremented by iparams.shift. */ - int GetBars() override { return GetCandle() PTR_DEREF GetBars(); } + int GetBars() override { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetBars(); + } /** * Returns index of the current bar. */ - virtual int GetBarIndex() { return GetCandle() PTR_DEREF GetBarIndex(); } + virtual int GetBarIndex() { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetBarIndex(); + } /** * Returns time of the bar for a given shift. @@ -1202,6 +1234,12 @@ class IndicatorData : public IndicatorBase { * Returns the index of the bar which covers the specified time. */ virtual int GetBarShift(datetime _time, bool _exact = false) { + if (GetTick() == THIS_PTR) { + Alert(GetFullName(), " tick indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + return GetTick() PTR_DEREF GetBarShift(_time, _exact); } @@ -1239,7 +1277,15 @@ class IndicatorData : public IndicatorBase { /** * Gets close price for a given, optional shift. */ - virtual double GetClose(int _shift = 0) { return GetCandle() PTR_DEREF GetClose(_shift); } + virtual double GetClose(int _shift = 0) { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetClose(_shift); + } /** * Returns the indicator's struct value via index. @@ -1254,7 +1300,15 @@ class IndicatorData : public IndicatorBase { /** * Gets high price for a given, optional shift. */ - virtual double GetHigh(int _shift = 0) { return GetCandle() PTR_DEREF GetHigh(_shift); } + virtual double GetHigh(int _shift = 0) { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetHigh(_shift); + } /** * Alters indicator's struct value. @@ -1269,30 +1323,57 @@ class IndicatorData : public IndicatorBase { /** * Returns the indicator's entry value. */ - virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) = 0; + virtual IndicatorDataEntryValue GetEntryValue(int _mode = 0, int _abs_shift = 0) override = 0; /** * Returns the shift of the maximum value over a specific number of periods depending on type. */ - virtual int GetHighest(int type, int _count = WHOLE_ARRAY, int _start = 0) { - return GetCandle() PTR_DEREF GetHighest(type, _count, _start); + virtual int GetHighest(int mode, int count = WHOLE_ARRAY, int start_bar = 0) { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + return GetCandle() PTR_DEREF GetHighest(mode, count, start_bar); } /** * Returns time of the last bar. */ - virtual datetime GetLastBarTime() { return GetCandle() PTR_DEREF GetLastBarTime(); } + virtual datetime GetLastBarTime() { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetLastBarTime(); + } /** * Gets low price for a given, optional shift. */ - virtual double GetLow(int _shift = 0) { return GetCandle() PTR_DEREF GetLow(_shift); } + virtual double GetLow(int _shift = 0) { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetLow(_shift); + } /** * Returns the shift of the minimum value over a specific number of periods depending on type. */ - virtual int GetLowest(int type, int _count = WHOLE_ARRAY, int _start = 0) { - return GetCandle() PTR_DEREF GetLowest(type, _count, _start); + virtual int GetLowest(int mode, int count = WHOLE_ARRAY, int start_bar = 0) { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetLowest(mode, count, start_bar); } /** @@ -1305,17 +1386,34 @@ class IndicatorData : public IndicatorBase { /** * Get name of the indicator. */ - virtual string GetName() { return EnumToString(GetType()); } + virtual string GetName() override { return EnumToString(GetType()); } /** * Gets open price for a given, optional shift. */ - virtual double GetOpen(int _shift = 0) { return GetCandle() PTR_DEREF GetOpen(_shift); } + virtual double GetOpen(int _shift = 0) { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetOpen(_shift); + } /** * Gets OHLC price values. */ - virtual BarOHLC GetOHLC(int _rel_shift = 0) { return GetCandle() PTR_DEREF GetOHLC(_rel_shift); } + virtual BarOHLC GetOHLC(int _rel_shift = 0) override { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + BarOHLC _empty; + return _empty; + } + + return GetCandle() PTR_DEREF GetOHLC(_rel_shift); + } /** * Get peak price at given number of bars. @@ -1323,6 +1421,12 @@ class IndicatorData : public IndicatorBase { * In case of error, check it via GetLastError(). */ virtual double GetPeakPrice(int _bars, int _mode, int _index) { + if (GetTick() == THIS_PTR) { + Alert(GetFullName(), " tick indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + return GetTick() PTR_DEREF GetPeakPrice(_bars, _mode, _index); } @@ -1330,6 +1434,12 @@ class IndicatorData : public IndicatorBase { * Returns the current price value given applied price type, symbol and timeframe. */ double GetPrice(ENUM_APPLIED_PRICE _ap, int _rel_shift = 0) override { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + return GetCandle() PTR_DEREF GetPrice(_ap, _rel_shift); } @@ -1345,7 +1455,15 @@ class IndicatorData : public IndicatorBase { * * If local history is empty (not loaded), function returns 0. */ - int64 GetSpread(int _shift = 0) override { return GetCandle() PTR_DEREF GetSpread(_shift); } + int64 GetSpread(int _shift = 0) override { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetSpread(_shift); + } /** * Returns spread in pips. @@ -1452,20 +1570,44 @@ class IndicatorData : public IndicatorBase { /** * Gets indicator's symbol. */ - virtual string GetSymbol() { return GetTick() PTR_DEREF GetSymbol(); } + virtual string GetSymbol() { + if (GetTick() == THIS_PTR) { + Alert(GetFullName(), " tick indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return ""; + } + + return GetTick() PTR_DEREF GetSymbol(); + } /** * Gets symbol info for active symbol. */ - virtual SymbolInfoProp GetSymbolProps() { return GetTick() PTR_DEREF GetSymbolProps(); } + virtual SymbolInfoProp GetSymbolProps() { + if (GetTick() == THIS_PTR) { + Alert(GetFullName(), " tick indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + SymbolInfoProp _empty; + return _empty; + } + + return GetTick() PTR_DEREF GetSymbolProps(); + } /** * Gets indicator's time-frame. */ - virtual ENUM_TIMEFRAMES GetTf() { return GetCandle() PTR_DEREF GetTf(); } + virtual ENUM_TIMEFRAMES GetTf() { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return (ENUM_TIMEFRAMES)-1; + } + + return GetCandle() PTR_DEREF GetTf(); + } /** - /** * Traverses source indicators' hierarchy and tries to find Ask, Bid, Spread, * Volume and Tick Volume-featured indicator. IndicatorTick satisfies such * requirements. @@ -1492,12 +1634,28 @@ class IndicatorData : public IndicatorBase { * * If local history is empty (not loaded), function returns 0. */ - virtual int64 GetTickVolume(int _shift = 0) { return GetCandle() PTR_DEREF GetTickVolume(_shift); } + virtual int64 GetTickVolume(int _shift = 0) { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetTickVolume(_shift); + } /** * Removes candle from the buffer. Used mainly for testing purposes. */ - virtual void InvalidateCandle(int _abs_shift = 0) { GetCandle() PTR_DEREF InvalidateCandle(_abs_shift); } + virtual void InvalidateCandle(int _abs_shift = 0) { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return; + } + + GetCandle() PTR_DEREF InvalidateCandle(_abs_shift); + } /** * Fetches historic ticks for a given time range. @@ -1792,7 +1950,15 @@ class IndicatorData : public IndicatorBase { /** * Returns current tick index (incremented every OnTick()). */ - virtual int GetTickIndex() { return GetTick() PTR_DEREF GetTickIndex(); } + virtual int GetTickIndex() { + if (GetTick() == THIS_PTR) { + Alert(GetFullName(), " tick indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetTick() PTR_DEREF GetTickIndex(); + } /** * Get indicator type. @@ -1820,7 +1986,15 @@ class IndicatorData : public IndicatorBase { * * If local history is empty (not loaded), function returns 0. */ - int64 GetVolume(int _shift = 0) override { return GetCandle() PTR_DEREF GetVolume(_shift); } + int64 GetVolume(int _shift = 0) override { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return -1; + } + + return GetCandle() PTR_DEREF GetVolume(_shift); + } /** * Sends entry to listening indicators. @@ -1868,7 +2042,15 @@ class IndicatorData : public IndicatorBase { /** * Check if there is a new bar to parse. */ - virtual bool IsNewBar() { return GetCandle() PTR_DEREF IsNewBar(); } + virtual bool IsNewBar() { + if (GetCandle() == THIS_PTR) { + Alert(GetFullName(), " candle indicator must override ", __FUNCTION__, "()!"); + DebugBreak(); + return false; + } + + return GetCandle() PTR_DEREF IsNewBar(); + } /** * Called when indicator became a data source for other indicator. @@ -1975,12 +2157,12 @@ class IndicatorData : public IndicatorBase { /** * Converts relative shift into absolute one. */ - virtual int ToAbsShift(int _rel_shift) = 0; + virtual int ToAbsShift(int _rel_shift) override = 0; /** * Converts absolute shift into relative one. */ - virtual int ToRelShift(int _abs_shift) = 0; + virtual int ToRelShift(int _abs_shift) override = 0; /** * Loads and validates built-in indicators whose can be used as data source. @@ -2034,7 +2216,7 @@ IValueStorage* ExternInstantiateIndicatorBufferValueStorageDouble::InstantiateIn } #ifndef __MQL__ -int GetBarsFromStart(IndicatorData* _indi) { return _indi PTR_DEREF GetBars(); } +int GetBarsFromStart(IndicatorBase* _indi) { return _indi PTR_DEREF GetBars(); } #endif #ifdef EMSCRIPTEN diff --git a/Indicator/tests/Makefile b/Indicator/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Indicator/tests/Makefile +++ b/Indicator/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Indicators/Bitwise/Indi_Candle.mqh b/Indicators/Bitwise/Indi_Candle.mqh index bd2bd31e0..1a286092d 100644 --- a/Indicators/Bitwise/Indi_Candle.mqh +++ b/Indicators/Bitwise/Indi_Candle.mqh @@ -26,9 +26,9 @@ #endif // Includes. -#include "../../Bar.struct.h" +#include "../../Platform/Chart/Bar.struct.h" #include "../../Indicator/Indicator.h" -#include "../../Pattern.struct.h" +#include "../../Platform/Chart/Pattern.struct.h" #include "../../Serializer/Serializer.h" #include "../../Storage/Dict/Buffer/BufferStruct.h" #include "../Price/Indi_Price.h" diff --git a/Indicators/Bitwise/Indi_Pattern.mqh b/Indicators/Bitwise/Indi_Pattern.mqh index 6ad40f135..13f805124 100644 --- a/Indicators/Bitwise/Indi_Pattern.mqh +++ b/Indicators/Bitwise/Indi_Pattern.mqh @@ -26,10 +26,10 @@ #endif // Includes. -#include "../../Bar.struct.h" +#include "../../Platform/Chart/Bar.struct.h" #include "../../Indicator/Indicator.define.h" #include "../../Indicator/Indicator.h" -#include "../../Pattern.struct.h" +#include "../../Platform/Chart/Pattern.struct.h" #include "../../Serializer/Serializer.h" #include "../../Storage/Dict/Buffer/BufferStruct.h" #include "../Price/Indi_Price.h" diff --git a/Indicators/Bitwise/tests/Makefile b/Indicators/Bitwise/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Indicators/Bitwise/tests/Makefile +++ b/Indicators/Bitwise/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Indicators/OHLC/tests/Makefile b/Indicators/OHLC/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Indicators/OHLC/tests/Makefile +++ b/Indicators/OHLC/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Indicators/Oscillator/tests/Makefile b/Indicators/Oscillator/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Indicators/Oscillator/tests/Makefile +++ b/Indicators/Oscillator/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Indicators/Price/tests/Makefile b/Indicators/Price/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Indicators/Price/tests/Makefile +++ b/Indicators/Price/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Indicators/PriceMulti/tests/Makefile b/Indicators/PriceMulti/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Indicators/PriceMulti/tests/Makefile +++ b/Indicators/PriceMulti/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Indicators/PriceRange/Indi_Pivot.h b/Indicators/PriceRange/Indi_Pivot.h index 47d45cfe7..c27387015 100644 --- a/Indicators/PriceRange/Indi_Pivot.h +++ b/Indicators/PriceRange/Indi_Pivot.h @@ -26,7 +26,7 @@ #endif // Includes. -#include "../../Bar.struct.h" +#include "../../Platform/Chart/Bar.struct.h" #include "../../Indicator/Indicator.struct.h" #include "../../Serializer/Serializer.h" #include "../Special/Indi_Math.mqh" diff --git a/Indicators/PriceRange/tests/Makefile b/Indicators/PriceRange/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Indicators/PriceRange/tests/Makefile +++ b/Indicators/PriceRange/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Indicators/Special/tests/Makefile b/Indicators/Special/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Indicators/Special/tests/Makefile +++ b/Indicators/Special/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Indicators/Tf/Indi_TfMt.h b/Indicators/Tf/Indi_TfMt.h index ae2f16811..36c6c215b 100644 --- a/Indicators/Tf/Indi_TfMt.h +++ b/Indicators/Tf/Indi_TfMt.h @@ -53,7 +53,10 @@ class Indi_TfMt : public IndicatorCandle(THIS_PTR)); } + void Init() { + SetName("Indi_TfMt"); + history.SetItemProvider(new ItemsHistoryTfMtCandleProvider(THIS_PTR)); + } public: /* Special methods */ diff --git a/Indicators/Tf/Indi_TfMt.provider.h b/Indicators/Tf/Indi_TfMt.provider.h index 55e9cf0e3..f1f5fb9c7 100644 --- a/Indicators/Tf/Indi_TfMt.provider.h +++ b/Indicators/Tf/Indi_TfMt.provider.h @@ -52,8 +52,8 @@ class ItemsHistoryTfMtCandleProvider : public ItemsHistoryCandleProvider { // Seconds per candle calculated from TF. int _spc = (int)ChartTf::TfToSeconds(indi PTR_DEREF GetTf()); - Print("Indi_TfMt's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | TIME_SECONDS), - ", ", _ask, ", ", _bid); + // Print("Indi_TfMt's history: New tick: ", TimeToString(_time_ms / 1000, TIME_DATE | TIME_MINUTES | TIME_SECONDS), + // ", ", _ask, ", ", _bid); // We know that tick's timestamp will be ahead of the last tick and thus // inside or ahead of the last created candle. In order to retrieve last diff --git a/Indicators/Tick/Indi_TickMt.h b/Indicators/Tick/Indi_TickMt.h index c2dcf44c8..89269bc5a 100644 --- a/Indicators/Tick/Indi_TickMt.h +++ b/Indicators/Tick/Indi_TickMt.h @@ -165,6 +165,7 @@ class Indi_TickMt : public IndicatorTick. - * - */ - -#ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once -#endif - -// Includes. -#include "Data.struct.h" -#include "Indicator/Indicator.struct.h" -#include "Math.define.h" -#include "Math.enum.h" -#include "Math.extern.h" -#include "Math.struct.h" - -/** - * Class to provide math related methods. - */ -class Math { - protected: - public: - Math() {} - - /* Calculation */ - - template - static X ReLU(X _value) { - return (X)fmax(0, _value); - } - - /** - * Returns value changed by the given percentage. - * - * @param double _value - * Base value to change. - * @param float _pct - * Percentage to change (1 is 100%). - * - * @return - * Returns value after the change. - */ - static double ChangeByPct(double _v, float _pct) { return _v != 0 ? _v + (fabs(_v) * _pct) : 0; } - - /** - * Calculates change between 2 values in percentage. - * - * @docs: https://stackoverflow.com/a/65511594/55075 - * - * @param double _v1 - * First value. - * @param double _v2 - * Second value. - * @param bool _hundreds - * When true, 100% is 100, otherwise 1. - * @return - * Returns percentage change. - */ - static double ChangeInPct(double _v1, double _v2, bool _hundreds = false) { - double _result = 0; - if (_v1 == 0 || _v2 == 0) { - // Change is zero when both values are zeros, otherwise it's 1 (100%). - _result = _v1 == 0 && _v2 == 0 ? 0 : 1; - } else { - // If values are non-zero, use the standard formula. - _result = (_v2 / _v1) - 1; - } - _result = _v2 > _v1 ? fabs(_result) : -fabs(_result); - return _hundreds ? _result * 100 : _result; - } - - /** - * Checks condition for 2 values based on the given comparison operator. - */ - template - static bool Compare(T1 _v1, T2 _v2, ENUM_MATH_CONDITION _op = MATH_COND_EQ) { - switch (_op) { - case MATH_COND_EQ: - return _v1 == _v2; - case MATH_COND_GT: - return _v1 > _v2; - case MATH_COND_LE: - return _v1 < _v2; - default: - break; - } - return false; - } - - /** - * Gets number of digits after decimal in a floating point number. - */ - template - static short FloatDigits(V _value) { - short _cnt = 0; - while ((int)_value != _value) { - _value *= 10; - _cnt++; - } - return _cnt; - } - - /** - * Returns a non-zero value. - * - * @return - * Returns a non-zero value. - */ - static double NonZero(double _v) { return _v == 0 ? DBL_MIN : _v; } - - /* Conditions */ - - /** - * Checks for math condition. - * - * @param ENUM_MATH_CONDITION _cond - * Math condition. - * @param MqlParam[] _args - * Condition arguments. - * @return - * Returns true when the condition is met. - */ - /* - bool CheckCondition(ENUM_MATH_CONDITION _cond, DataParamEntry &_args[]) { - switch (_cond) { - case MATH_COND_EQ: - // @todo - return false; - case MATH_COND_GT: - // @todo - return false; - case MATH_COND_LE: - // @todo - return false; - default: - // logger.Error(StringFormat("Invalid math condition: %s!", EnumToString(_cond), __FUNCTION_LINE__)); - return false; - } - } - bool CheckCondition(ENUM_MATH_CONDITION _cond) { - DataParamEntry _args[] = {}; - return Math::CheckCondition(_cond, _args); - } - */ - - template - static T Add(T a, T b) { - return a + b; - } - template - static T Sub(T a, T b) { - return a - b; - } - template - static T Mul(T a, T b) { - return a * b; - } - template - static T Div(T a, T b) { - return a / b; - } - template - static T Sin(T a) { - return sin(a); - } - template - static T Cos(T a) { - return cos(a); - } - template - static T Tang(T a) { - return tan(a); - } - template - static T Min(T a, T b) { - return MathMin(a, b); - } - template - static T Min(T a, T b, T c) { - return MathMin(MathMin(a, b), c); - } - template - static T Min(T a, T b, T c, T d) { - return MathMin(MathMin(MathMin(a, b), c), d); - } - template - static T Max(T a, T b) { - return MathMax(a, b); - } - template - static T Max(T a, T b, T c) { - return MathMax(MathMax(a, b), c); - } - template - static T Max(T a, T b, T c, T d) { - return MathMax(MathMax(MathMax(a, b), c), d); - } - template - static T Avg(T a, T b) { - return (a + b) / 2; - } - template - static T Avg(T a, T b, T c) { - return (a + b + c) / 3; - } - template - static T Avg(T a, T b, T c, T d) { - return (a + b + c + d) / 4; - } - template - static T Abs(T a) { - return MathAbs(a); - } - - template - static T Op(ENUM_MATH_OP _op, T _val_1, T _val_2 = 0) { - switch (_op) { - case MATH_OP_ADD: - return Add(_val_1, _val_2); - case MATH_OP_SUB: - return Sub(_val_1, _val_2); - case MATH_OP_MUL: - return Mul(_val_1, _val_2); - case MATH_OP_DIV: - return Div(_val_1, _val_2); - case MATH_OP_SIN: - return Sin(_val_1); - case MATH_OP_COS: - return Cos(_val_2); - case MATH_OP_TAN: - return Tang(_val_2); - case MATH_OP_MIN: - return Min(_val_1, _val_2); - case MATH_OP_MAX: - return Max(_val_1, _val_2); - case MATH_OP_AVG: - return Avg(_val_1, _val_2); - case MATH_OP_RELU: - return ReLU(_val_1); - case MATH_OP_ABS: - return Abs(_val_1); - case MATH_OP_ABS_DIFF: - return Abs(_val_1 - _val_2); - default: - return EMPTY_VALUE; - } - } -}; diff --git a/Math/Math.h b/Math/Math.h index 04d27f20b..7e55b2581 100644 --- a/Math/Math.h +++ b/Math/Math.h @@ -21,8 +21,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -264,7 +264,7 @@ class Math { int data_count = ArraySize(probability); if (data_count == 0) return false; - int error_code = 0, i; + int i; ArrayResize(result, data_count); //--- case sigma==0 @@ -402,8 +402,6 @@ class Math { return true; } - int err_code = 0; - for (i = 0; i < data_count; i++) { result[i] = RandomNonZero(); } diff --git a/Math/Matrix.h b/Math/Matrix.h index 1733501c6..916d7cb6f 100644 --- a/Math/Matrix.h +++ b/Math/Matrix.h @@ -2538,13 +2538,9 @@ class Matrix { void FromString(string text) { ARRAY(MatrixDimension*, _dimensions), *_root_dimension = NULL; - int _dimensions_length[MATRIX_DIMENSIONS] = {0, 0, 0, 0, 0}; int i, _number_start_pos; - bool _had_values; X _number; bool _expecting_value_or_child = true; - bool _expecting_comma = false; - bool _expecting_end = false; for (i = 0; i < StringLen(text); ++i) { unsigned short _char = StringGetCharacter(text, i), c; @@ -2556,8 +2552,6 @@ class Matrix { return; } - _had_values = false; - if (ArraySize(_dimensions) != 0) { _dimensions[ArraySize(_dimensions) - 1].type = MATRIX_DIMENSION_TYPE_CONTAINERS; } @@ -2574,13 +2568,11 @@ class Matrix { } _expecting_value_or_child = true; - _expecting_end = true; break; case ']': ArrayResize(_dimensions, ArraySize(_dimensions) - 1, MATRIX_DIMENSIONS); _expecting_value_or_child = true; - _expecting_comma = false; break; case '0': @@ -2609,15 +2601,11 @@ class Matrix { i -= 2; _dimensions[ArraySize(_dimensions) - 1].type = MATRIX_DIMENSION_TYPE_VALUES; _dimensions[ArraySize(_dimensions) - 1].AddValue(_number); - _expecting_end = true; _expecting_value_or_child = true; - _expecting_comma = false; break; case ',': _expecting_value_or_child = true; - _expecting_comma = false; - _expecting_end = false; break; case ' ': case '\t': diff --git a/Math/tests/Makefile b/Math/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Math/tests/Makefile +++ b/Math/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Bar.enum.h b/Platform/Chart/Bar.enum.h similarity index 100% rename from Bar.enum.h rename to Platform/Chart/Bar.enum.h diff --git a/Bar.struct.h b/Platform/Chart/Bar.struct.h similarity index 98% rename from Bar.struct.h rename to Platform/Chart/Bar.struct.h index f931af0a4..6b372d08f 100644 --- a/Bar.struct.h +++ b/Platform/Chart/Bar.struct.h @@ -35,12 +35,12 @@ class Serializer; // Includes. #include "Bar.enum.h" -#include "Platform/Chart/Chart.enum.h" -#include "Serializer/Serializable.h" -#include "Serializer/Serializer.enum.h" -#include "Serializer/Serializer.h" -#include "Serializer/SerializerNode.enum.h" -#include "Std.h" +#include "Chart.enum.h" +#include "../../Serializer/Serializable.h" +#include "../../Serializer/Serializer.enum.h" +#include "../../Serializer/Serializer.h" +#include "../../Serializer/SerializerNode.enum.h" +#include "../../Std.h" /* Struct for storing OHLC values. */ struct BarOHLC diff --git a/Candle.struct.h b/Platform/Chart/Candle.struct.h similarity index 98% rename from Candle.struct.h rename to Platform/Chart/Candle.struct.h index 4d01e0474..55d0da7aa 100644 --- a/Candle.struct.h +++ b/Platform/Chart/Candle.struct.h @@ -35,12 +35,12 @@ class Serializer; // Includes. #include "Bar.enum.h" -#include "Platform/Chart/Chart.enum.h" -#include "Serializer/Serializable.h" -#include "Serializer/Serializer.enum.h" -#include "Serializer/Serializer.h" -#include "Serializer/SerializerNode.enum.h" -#include "Std.h" +#include "Chart.enum.h" +#include "../../Serializer/Serializable.h" +#include "../../Serializer/Serializer.enum.h" +#include "../../Serializer/Serializer.h" +#include "../../Serializer/SerializerNode.enum.h" +#include "../../Std.h" /* Structure for storing OHLC values. */ template diff --git a/Platform/Chart/Chart.define.h b/Platform/Chart/Chart.define.h index 653898359..74828c597 100644 --- a/Platform/Chart/Chart.define.h +++ b/Platform/Chart/Chart.define.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif /* Defines */ @@ -56,51 +56,56 @@ #define MN1B (1 << MN1) // Monthly #ifndef __MQL4__ -// Chart. -#define CHART_BAR 0 -#define CHART_CANDLE 1 -//--- -#ifndef MODE_ASCEND -#define MODE_ASCEND 0 + // Chart. + #define CHART_BAR 0 + #define CHART_CANDLE 1 + //--- + #ifndef MODE_ASCEND + #define MODE_ASCEND 0 + #endif + #ifndef MODE_DESCEND + #define MODE_DESCEND 1 + #endif + //--- + #define MODE_LOW 1 + #define MODE_HIGH 2 + // -- + #define MODE_OPEN 0 + #define MODE_CLOSE 3 + #define MODE_VOLUME 4 + // -- + #define MODE_TIME \ + 6 // Used to retrieve time from Candle indicator. Changed value from 5 to 6 in order to prevent conflicts with + // MODE_REAL_VOLUME. + #define MODE_BID 9 + #define MODE_ASK 10 + #define MODE_POINT 11 + #define MODE_DIGITS 12 + #define MODE_SPREAD 13 + #define MODE_STOPLEVEL 14 + #define MODE_LOTSIZE 15 + #define MODE_TICKVALUE 16 + #define MODE_TICKSIZE 17 + #define MODE_SWAPLONG 18 + #define MODE_SWAPSHORT 19 + #define MODE_STARTING 20 + #define MODE_EXPIRATION 21 + #define MODE_TRADEALLOWED 22 + #define MODE_TICK_SIZE 21 + #define MODE_TICK_VALUE 22 + #define MODE_MINLOT 23 + #define MODE_LOTSTEP 24 + #define MODE_MAXLOT 25 + #define MODE_SWAPTYPE 26 + #define MODE_PROFITCALCMODE 27 + #define MODE_MARGINCALCMODE 28 + #define MODE_MARGININIT 29 + #define MODE_MARGINMAINTENANCE 30 + #define MODE_MARGINHEDGED 31 + #define MODE_MARGINREQUIRED 32 + #define MODE_FREEZELEVEL 33 #endif -#ifndef MODE_DESCEND -#define MODE_DESCEND 1 -#endif -//--- -#define MODE_LOW 1 -#define MODE_HIGH 2 -// -- -#define MODE_OPEN 0 -#define MODE_CLOSE 3 -#define MODE_VOLUME 4 -#define MODE_REAL_VOLUME 5 -// -- -#define MODE_TIME 5 -#define MODE_BID 9 -#define MODE_ASK 10 -#define MODE_POINT 11 -#define MODE_DIGITS 12 -#define MODE_SPREAD 13 -#define MODE_STOPLEVEL 14 -#define MODE_LOTSIZE 15 -#define MODE_TICKVALUE 16 -#define MODE_TICKSIZE 17 -#define MODE_SWAPLONG 18 -#define MODE_SWAPSHORT 19 -#define MODE_STARTING 20 -#define MODE_EXPIRATION 21 -#define MODE_TRADEALLOWED 22 -#define MODE_TICK_SIZE 21 -#define MODE_TICK_VALUE 22 -#define MODE_MINLOT 23 -#define MODE_LOTSTEP 24 -#define MODE_MAXLOT 25 -#define MODE_SWAPTYPE 26 -#define MODE_PROFITCALCMODE 27 -#define MODE_MARGINCALCMODE 28 -#define MODE_MARGININIT 29 -#define MODE_MARGINMAINTENANCE 30 -#define MODE_MARGINHEDGED 31 -#define MODE_MARGINREQUIRED 32 -#define MODE_FREEZELEVEL 33 + +#ifndef __MQL5__ + #define MODE_REAL_VOLUME 7 #endif diff --git a/Platform/Chart/Chart.struct.h b/Platform/Chart/Chart.struct.h index ef0d2e3f0..d7a690c06 100644 --- a/Platform/Chart/Chart.struct.h +++ b/Platform/Chart/Chart.struct.h @@ -35,7 +35,7 @@ class Class; struct ChartTf; // Includes. -#include "../../Bar.struct.h" +#include "Bar.struct.h" #include "../../Serializer/Serializer.h" #include "../../Serializer/SerializerNode.enum.h" #include "../../Std.h" diff --git a/Pattern.enum.h b/Platform/Chart/Pattern.enum.h similarity index 100% rename from Pattern.enum.h rename to Platform/Chart/Pattern.enum.h diff --git a/Pattern.mqh b/Platform/Chart/Pattern.h similarity index 100% rename from Pattern.mqh rename to Platform/Chart/Pattern.h diff --git a/Pattern.struct.h b/Platform/Chart/Pattern.struct.h similarity index 99% rename from Pattern.struct.h rename to Platform/Chart/Pattern.struct.h index f8aebe7d8..4a0377287 100644 --- a/Pattern.struct.h +++ b/Platform/Chart/Pattern.struct.h @@ -32,7 +32,7 @@ // Includes. #include "Bar.struct.h" -#include "Math/Math.define.h" +#include "../../Math/Math.define.h" #include "Pattern.enum.h" // Defines structure for bitwise pattern values. diff --git a/Platform/Chart/tests/Chart.test.mq5 b/Platform/Chart/tests/Chart.test.mq5 index f3b9f9779..10875e102 100644 --- a/Platform/Chart/tests/Chart.test.mq5 +++ b/Platform/Chart/tests/Chart.test.mq5 @@ -25,6 +25,8 @@ */ // Includes. +#include "../Bar.struct.h" +#include "../Candle.struct.h" #include "../Chart.h" #include "../../../Convert.mqh" #include "../../../Test.mqh" diff --git a/Platform/Chart/tests/Makefile b/Platform/Chart/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Platform/Chart/tests/Makefile +++ b/Platform/Chart/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Platform/Chart3D/Chart3D.h b/Platform/Chart3D/Chart3D.h index 4f9cbcd64..9148a3987 100644 --- a/Platform/Chart3D/Chart3D.h +++ b/Platform/Chart3D/Chart3D.h @@ -26,28 +26,31 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -#include "../../Bar.struct.h" -#include "../../Indicator/IndicatorData.h" -#include "../../Indicators/Price/Indi_MA.h" -#include "../../Instances.h" -#include "../../Refs.mqh" -#include "../../Serializer/SerializerConverter.h" -#include "../../Serializer/SerializerJson.h" -#include "Chart3DCandles.h" -#include "Chart3DType.h" -#include "Cube.h" -#include "Device.h" -#include "Interface.h" - -#ifdef __MQL5__ -// Resource variables. -#resource "Shaders/chart3d_vs.hlsl" as string Chart3DShaderSourceVS; -#resource "Shaders/chart3d_ps.hlsl" as string Chart3DShaderSourcePS; -#endif +// We currently only support MQL. +#ifdef __MQL__ + + #include "../../Indicator/IndicatorData.h" + #include "../../Indicators/Price/Indi_MA.h" + #include "../../Refs.mqh" + #include "../../Serializer/SerializerConverter.h" + #include "../../Serializer/SerializerJson.h" + #include "../../Storage/Instances.h" + #include "../Chart/Bar.struct.h" + #include "Chart3DCandles.h" + #include "Chart3DType.h" + #include "Cube.h" + #include "Device.h" + #include "Interface.h" + + #ifdef __MQL5__ + // Resource variables. + #resource "Shaders/chart3d_vs.hlsl" as string Chart3DShaderSourceVS; + #resource "Shaders/chart3d_ps.hlsl" as string Chart3DShaderSourcePS; + #endif typedef BarOHLC (*Chart3DPriceFetcher)(ENUM_TIMEFRAMES, int); @@ -100,9 +103,9 @@ class Chart3D : public Dynamic { offset.z = 25.0f; initialized = false; source = _source; -#ifdef __MQL5__ + #ifdef __MQL5__ Interface::AddListener(chart3d_interface_listener, &this); -#endif + #endif } void OnInterfaceEvent(InterfaceEvent& _event) { @@ -207,7 +210,9 @@ class Chart3D : public Dynamic { float _scale_y = 40.0f; float _price_min = GetMinBarsPrice(); float _price_max = GetMaxBarsPrice(); - float _result = 1.0f / (_price_max - _price_min) * (price - _price_min) * _scale_y - (_scale_y / 2); + float _result = (_price_max - _price_min == 0.0f) + ? 1.0f + : (1.0f / (_price_max - _price_min) * (price - _price_min) * _scale_y - (_scale_y / 2)); return _result; } @@ -220,10 +225,12 @@ class Chart3D : public Dynamic { BarOHLC _ohlc; // BarOHLC _ohlc = price_fetcher(PERIOD_CURRENT, 0); // @fixme: 'price_fetcher' - internal error #%d -#ifdef __debug__ + #ifdef __debug__ Print(SerializerConverter::FromObject(_ohlc).ToString()); -#endif + #endif _type_renderer.Render(_device); } }; + +#endif diff --git a/Platform/Chart3D/Device.h b/Platform/Chart3D/Device.h index 741561a51..85ceefe12 100644 --- a/Platform/Chart3D/Device.h +++ b/Platform/Chart3D/Device.h @@ -26,20 +26,23 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -#include "../../Refs.mqh" -#include "../../Util.h" -#include "Frontend.h" -#include "IndexBuffer.h" -#include "Material.h" -#include "Math.h" -#include "Mesh.h" -#include "Shader.h" -#include "ShaderVertexLayout.struct.h" -#include "VertexBuffer.h" +// We currently only support MQL. +#ifdef __MQL__ + + #include "../../Refs.mqh" + #include "../../Util.h" + #include "Frontend.h" + #include "IndexBuffer.h" + #include "Material.h" + #include "Math.h" + #include "Mesh.h" + #include "Shader.h" + #include "ShaderVertexLayout.struct.h" + #include "VertexBuffer.h" enum GFX_DRAW_TEXT_FLAGS { GFX_DRAW_TEXT_FLAG_NONE, GFX_DRAW_TEXT_FLAG_2D_COORD_X, GFX_DRAW_TEXT_FLAG_2D_COORD_Y }; @@ -165,10 +168,10 @@ class Device : public Dynamic { VertexBuffer* _buff = CreateVertexBuffer(); // Unfortunately we can't make this method virtual. if (dynamic_cast(_buff) != NULL) { -// MT5's DirectX. -#ifdef __debug__ + // MT5's DirectX. + #ifdef __debug__ Print("Filling vertex buffer via MTDXVertexBuffer"); -#endif + #endif ((MTDXVertexBuffer*)_buff).Fill(data); } else { Alert("Unsupported vertex buffer device target"); @@ -196,9 +199,9 @@ class Device : public Dynamic { */ template void Render(Mesh* _mesh, Shader* _vs = NULL, Shader* _ps = NULL) { -#ifdef __debug__ + #ifdef __debug__ Print("Rendering mesh"); -#endif + #endif VertexBuffer* _vertices; IndexBuffer* _indices; _mesh.GetBuffers(&this, _vertices, _indices); @@ -321,3 +324,5 @@ class Device : public Dynamic { */ virtual void ClearBuffer(ENUM_CLEAR_BUFFER_TYPE _type, unsigned int _color) = NULL; }; + +#endif diff --git a/Platform/Chart3D/Devices/MTDX/MTDXDevice.h b/Platform/Chart3D/Devices/MTDX/MTDXDevice.h index aa82926c8..82a505d2b 100644 --- a/Platform/Chart3D/Devices/MTDX/MTDXDevice.h +++ b/Platform/Chart3D/Devices/MTDX/MTDXDevice.h @@ -26,11 +26,14 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -#include "../../Device.h" +// We currently only support MQL. +#ifdef __MQL__ + + #include "../../Device.h" class MTDXDevice : public Device { public: @@ -38,14 +41,14 @@ class MTDXDevice : public Device { * Initializes graphics device. */ bool Init(Frontend* _frontend) { -#ifdef __debug__ + #ifdef __debug__ Print("MTDXDevice: DXContextCreate: width = ", _frontend.Width(), ", height = ", _frontend.Height()); -#endif + #endif context = DXContextCreate(_frontend.Width(), _frontend.Height()); -#ifdef __debug__ + #ifdef __debug__ Print("LastError: ", GetLastError()); Print("MTDXDevice: context = ", context); -#endif + #endif _frontend.Init(); return true; } @@ -87,14 +90,14 @@ class MTDXDevice : public Device { _dx_color.z = 1.0f / 255.0f * ((_color & 0x000000FF) >> 0); _dx_color.w = 1.0f / 255.0f * ((_color & 0xFF000000) >> 24); DXContextClearColors(context, _dx_color); -#ifdef __debug__ + #ifdef __debug__ Print("DXContextClearColors: LastError: ", GetLastError()); -#endif + #endif } else if (_type == CLEAR_BUFFER_TYPE_DEPTH) { DXContextClearDepth(context); -#ifdef __debug__ + #ifdef __debug__ Print("DXContextClearDepth: LastError: ", GetLastError()); -#endif + #endif } } @@ -140,19 +143,21 @@ class MTDXDevice : public Device { _vertices.Select(); if (_indices == NULL) { if (!DXDraw(context)) { -#ifdef __debug__ + #ifdef __debug__ Print("Can't draw!"); -#endif + #endif } -#ifdef __debug__ + #ifdef __debug__ Print("DXDraw: LastError: ", GetLastError()); -#endif + #endif } else { _indices.Select(); DXDrawIndexed(context); -#ifdef __debug__ + #ifdef __debug__ Print("DXDrawIndexed: LastError: ", GetLastError()); -#endif + #endif } } }; + +#endif diff --git a/Platform/Chart3D/Face.h b/Platform/Chart3D/Face.h index 59f394b26..4969db0d2 100644 --- a/Platform/Chart3D/Face.h +++ b/Platform/Chart3D/Face.h @@ -26,11 +26,14 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -#include "Math.h" +// We currently only support MQL. +#ifdef __MQL__ + + #include "Math.h" // Face flags. enum ENUM_FACE_FLAGS { FACE_FLAGS_NONE, FACE_FLAGS_TRIANGLE, FACE_FLAGS_QUAD }; @@ -99,3 +102,5 @@ struct Face { } } }; + +#endif diff --git a/Platform/Chart3D/Frontend.h b/Platform/Chart3D/Frontend.h index a5bc188eb..d681b1552 100644 --- a/Platform/Chart3D/Frontend.h +++ b/Platform/Chart3D/Frontend.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif #include "../../Refs.mqh" @@ -61,32 +61,32 @@ class Frontend : public Dynamic { /** * Initializes canvas. */ - virtual bool Init() = NULL; + virtual bool Init() = 0; /** * Deinitializes canvas. */ - virtual bool Deinit() = NULL; + virtual bool Deinit() = 0; /** * Executed before render starts. */ - virtual void RenderBegin(int context) = NULL; + virtual void RenderBegin(int context) = 0; /** * Executed after render ends. */ - virtual void RenderEnd(int context) = NULL; + virtual void RenderEnd(int context) = 0; /** * Returns canvas' width. */ - virtual int Width() = NULL; + virtual int Width() = 0; /** * Returns canvas' height. */ - virtual int Height() = NULL; + virtual int Height() = 0; /** * Enqueues text to be drawn directly into the pixel buffer. Queue will be processed in the Device::End() method. diff --git a/Platform/Chart3D/IndexBuffer.h b/Platform/Chart3D/IndexBuffer.h index 7392f7731..3eb7f7395 100644 --- a/Platform/Chart3D/IndexBuffer.h +++ b/Platform/Chart3D/IndexBuffer.h @@ -26,8 +26,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif #include "../../Refs.mqh" @@ -54,15 +54,15 @@ class IndexBuffer : public Dynamic { /** * Creates index buffer. */ - virtual bool Create(VOID_DATA(_data)) = NULL; + virtual bool Create(VOID_DATA(_data)) = 0; /** * Fills index buffer with indices. */ - virtual void Fill(ARRAY_REF(unsigned int, _indices)) = NULL; + virtual void Fill(ARRAY_REF(unsigned int, _indices)) = 0; /** * Activates index buffer for rendering. */ - virtual void Select() = NULL; + virtual void Select() = 0; }; diff --git a/Platform/Chart3D/Math.h b/Platform/Chart3D/Math.h index 25cd12e1d..69a0e3947 100644 --- a/Platform/Chart3D/Math.h +++ b/Platform/Chart3D/Math.h @@ -4,34 +4,38 @@ //| https://www.mql5.com | //+------------------------------------------------------------------+ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif #ifdef __MQL__ -#property copyright "Copyright 2019,MetaQuotes Software Corp." -#property link "https://www.mql5.com" + #property copyright "Copyright 2019,MetaQuotes Software Corp." + #property link "https://www.mql5.com" #endif + +// We currently only support MQL. +#ifdef __MQL__ + //+------------------------------------------------------------------+ -//| DirectX Math Routines | -//+------------------------------------------------------------------+ -//| Ported from C++ code of ReactOS, written by David Adam | -//| and Tony Wasserka | -//| | -//| https://doxygen.reactos.org/de/d57/ | -//| dll_2directx_2wine_2d3dx9__36_2math_8c_source.html | -//| | -//| Copyright (C) 2007 David Adam | -//| Copyright (C) 2007 Tony Wasserka | -//+------------------------------------------------------------------+ -#define DX_PI 3.1415926535897932384626f -#define DX_PI_DIV2 1.5707963267948966192313f -#define DX_PI_DIV3 1.0471975511965977461542f -#define DX_PI_DIV4 0.7853981633974483096156f -#define DX_PI_DIV6 0.5235987755982988730771f -#define DX_PI_MUL2 6.2831853071795864769253f -#define DXSH_MINORDER 2 -#define DXSH_MAXORDER 6 + //| DirectX Math Routines | + //+------------------------------------------------------------------+ + //| Ported from C++ code of ReactOS, written by David Adam | + //| and Tony Wasserka | + //| | + //| https://doxygen.reactos.org/de/d57/ | + //| dll_2directx_2wine_2d3dx9__36_2math_8c_source.html | + //| | + //| Copyright (C) 2007 David Adam | + //| Copyright (C) 2007 Tony Wasserka | + //+------------------------------------------------------------------+ + #define DX_PI 3.1415926535897932384626f + #define DX_PI_DIV2 1.5707963267948966192313f + #define DX_PI_DIV3 1.0471975511965977461542f + #define DX_PI_DIV4 0.7853981633974483096156f + #define DX_PI_DIV6 0.5235987755982988730771f + #define DX_PI_MUL2 6.2831853071795864769253f + #define DXSH_MINORDER 2 + #define DXSH_MAXORDER 6 //+------------------------------------------------------------------+ //| Preliminary declarations | //+------------------------------------------------------------------+ @@ -1442,7 +1446,7 @@ void DXMatrixAffineTransformation2D(DXMatrix &out, float scaling, const DXVector out.m[3][0] += translation.x; out.m[3][1] += translation.y; } -#define D3DERR_INVALIDCALL -2005530516 + #define D3DERR_INVALIDCALL -2005530516 //#define S_OK 0; //+------------------------------------------------------------------+ //| Breaks down a general 3D transformation _matrix into its scalar, | @@ -3150,7 +3154,7 @@ void DXSHRotate(float &out[], int order, const DXMatrix &_matrix, const float &i return; } -#ifdef __MQL5__ + #ifdef __MQL5__ if ((float)fabs(_matrix.m[2][2]) != 1.0f) { sinb = (float)sqrt(1.0f - _matrix.m[2][2] * _matrix.m[2][2]); alpha = (float)atan2(_matrix.m[2][1] / sinb, _matrix.m[2][0] / sinb); @@ -3161,12 +3165,12 @@ void DXSHRotate(float &out[], int order, const DXMatrix &_matrix, const float &i beta = 0.0f; gamma = 0.0f; } -#else + #else alpha = 0.0f; beta = 0.0f; gamma = 0.0f; sinb = 0.0f; -#endif + #endif //--- DXSHRotateZ(temp, order, gamma, in); @@ -3230,3 +3234,5 @@ float DXScalarLerp(const float val1, const float val2, float s) { return ((1 - s //+---------------------------------------------------------------------+ float DXScalarBiasScale(const float val, const float bias, const float scale) { return ((val + bias) * scale); } //+------------------------------------------------------------------+ + +#endif diff --git a/Platform/Chart3D/Shader.h b/Platform/Chart3D/Shader.h index 8bfc3de25..6b5d9cfca 100644 --- a/Platform/Chart3D/Shader.h +++ b/Platform/Chart3D/Shader.h @@ -26,11 +26,14 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -#include "../../Refs.mqh" +// We currently only support MQL. +#ifdef __MQL__ + + #include "../../Refs.mqh" // Shader type. enum ENUM_SHADER_TYPE { @@ -85,10 +88,10 @@ class Shader : public Dynamic { void SetCBuffer(const X& data) { // Unfortunately we can't make this method virtual. if (dynamic_cast(&this) != NULL) { -// MT5's DirectX. -#ifdef __debug__ + // MT5's DirectX. + #ifdef __debug__ Print("Setting CBuffer data for MT5"); -#endif + #endif ((MTDXShader*)&this).SetCBuffer(data); } else { Alert("Unsupported cbuffer device target"); @@ -100,3 +103,5 @@ class Shader : public Dynamic { */ virtual void Select() = NULL; }; + +#endif diff --git a/Platform/Chart3D/TSR.h b/Platform/Chart3D/TSR.h index 4ed42dd48..e239a8ed5 100644 --- a/Platform/Chart3D/TSR.h +++ b/Platform/Chart3D/TSR.h @@ -26,11 +26,14 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -#include "Math.h" +// We currently only support MQL. +#ifdef __MQL__ + + #include "Math.h" class TSR { public: @@ -65,3 +68,5 @@ class TSR { return _mtx_result; } }; + +#endif diff --git a/Platform/Chart3D/Vertex.h b/Platform/Chart3D/Vertex.h index 65e9248b0..1922a8e62 100644 --- a/Platform/Chart3D/Vertex.h +++ b/Platform/Chart3D/Vertex.h @@ -21,11 +21,14 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif -#include "../../Refs.mqh" +// We currently only support MQL. +#ifdef __MQL__ + + #include "../../Refs.mqh" /** * Generic vertex to be used by meshes. @@ -56,3 +59,5 @@ const ShaderVertexLayout Vertex::Layout[3] = { {"POSITION", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), 0}, {"NORMAL", 0, GFX_VAR_TYPE_FLOAT, 3, false, sizeof(Vertex), sizeof(float) * 3}, {"COLOR", 0, GFX_VAR_TYPE_FLOAT, 4, false, sizeof(Vertex), sizeof(float) * 6}}; + +#endif diff --git a/Platform/Chart3D/tests/Chart3D.test.mq5 b/Platform/Chart3D/tests/Chart3D.test.mq5 index 22d2552d5..8bb1bba73 100644 --- a/Platform/Chart3D/tests/Chart3D.test.mq5 +++ b/Platform/Chart3D/tests/Chart3D.test.mq5 @@ -26,25 +26,25 @@ #ifdef __MQL5__ -//#define __debug__ - -// Resources. -#resource "Shaders/vertex.hlsl" as string ShaderSourceVS; -#resource "Shaders/pixel.hlsl" as string ShaderSourcePS; - -// Includes. -#include "../Chart3D.h" -#include "../Cube.h" -#include "../Devices/MTDX/MTDXDevice.h" -#include "../Devices/MTDX/MTDXIndexBuffer.h" -#include "../Devices/MTDX/MTDXShader.h" -#include "../Devices/MTDX/MTDXVertexBuffer.h" -#include "../Frontends/MT5Frontend.h" -#include "../../../Storage/Dict/Buffer/BufferStruct.h" -#include "../../Chart/Chart.h" -#include "../../Platform.h" -#include "../../../Serializer/Serializer.h" -#include "../../../Test.mqh" + //#define __debug__ + + // Resources. + #resource "Shaders/vertex.hlsl" as string ShaderSourceVS; + #resource "Shaders/pixel.hlsl" as string ShaderSourcePS; + + // Includes. + #include "../../../Serializer/Serializer.h" + #include "../../../Storage/Dict/Buffer/BufferStruct.h" + #include "../../../Test.mqh" + #include "../../Chart/Chart.h" + #include "../../Platform.h" + #include "../Chart3D.h" + #include "../Cube.h" + #include "../Devices/MTDX/MTDXDevice.h" + #include "../Devices/MTDX/MTDXIndexBuffer.h" + #include "../Devices/MTDX/MTDXShader.h" + #include "../Devices/MTDX/MTDXVertexBuffer.h" + #include "../Frontends/MT5Frontend.h" /** * Implements OnInit(). @@ -93,7 +93,8 @@ int OnInit() { gfx.End(); - // break; + // Rendering one frame is enough. + break; } } diff --git a/Platform/Chart3D/tests/Makefile b/Platform/Chart3D/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Platform/Chart3D/tests/Makefile +++ b/Platform/Chart3D/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Platform/Order.h b/Platform/Order.h index 88ccbf307..e2f232d2e 100644 --- a/Platform/Order.h +++ b/Platform/Order.h @@ -1774,8 +1774,6 @@ class Order : public SymbolInfo { * Update specific double value of the current order. */ bool RefreshDummy(ENUM_ORDER_PROPERTY_DOUBLE _prop_id) { - bool _result = false; - double _value = WRONG_VALUE; ResetLastError(); switch (_prop_id) { case ORDER_PRICE_CURRENT: @@ -2850,14 +2848,14 @@ class Order : public SymbolInfo { bool ExecuteAction(ENUM_ORDER_ACTION _action, ARRAY_REF(DataParamEntry, _args)) { switch (_action) { case ORDER_ACTION_CLOSE: - switch (oparams.dummy) { - case false: - return ArraySize(_args) > 0 ? OrderClose((ENUM_ORDER_REASON_CLOSE)_args[0].integer_value) - : OrderClose(ORDER_REASON_CLOSED_BY_ACTION); - case true: - return ArraySize(_args) > 0 ? OrderCloseDummy((ENUM_ORDER_REASON_CLOSE)_args[0].integer_value) - : OrderCloseDummy(ORDER_REASON_CLOSED_BY_ACTION); + if (oparams.dummy) { + return ArraySize(_args) > 0 ? OrderCloseDummy((ENUM_ORDER_REASON_CLOSE)_args[0].integer_value) + : OrderCloseDummy(ORDER_REASON_CLOSED_BY_ACTION); + } else { + return ArraySize(_args) > 0 ? OrderClose((ENUM_ORDER_REASON_CLOSE)_args[0].integer_value) + : OrderClose(ORDER_REASON_CLOSED_BY_ACTION); } + break; case ORDER_ACTION_OPEN: return !oparams.dummy ? OrderSend() >= 0 : OrderSendDummy() >= 0; case ORDER_ACTION_COND_CLOSE_ADD: diff --git a/Platform/Order.struct.h b/Platform/Order.struct.h index 7d5411688..db37432dd 100644 --- a/Platform/Order.struct.h +++ b/Platform/Order.struct.h @@ -270,8 +270,7 @@ struct OrderData { double volume_init; // Initial volume. public: OrderData() - : close_tries(0), - magic(0), + : magic(0), position_id(0), position_by_id(0), ticket(0), @@ -279,6 +278,7 @@ struct OrderData { comment(""), commission(0), profit(0), + total_profit(0), price_open(0), price_close(0), price_current(0), @@ -294,6 +294,7 @@ struct OrderData { time_setup_msc(0), sl(0), tp(0), + close_tries(0), last_error(ERR_NO_ERROR), symbol(NULL), volume_curr(0), @@ -398,6 +399,9 @@ struct OrderData { case ORDER_POSITION_BY_ID: return (T)position_by_id; case ORDER_REASON: + #ifndef __MQL__ + case __ORDER_REASON: + #endif return (T)reason; case ORDER_TICKET: return (T)ticket; @@ -413,6 +417,9 @@ struct OrderData { return comment; #ifndef __MQL4__ case ORDER_EXTERNAL_ID: + #ifndef __MQL__ + case __ORDER_EXTERNAL_ID: + #endif return ext_id; #endif case ORDER_SYMBOL: @@ -631,6 +638,9 @@ struct OrderData { position_by_id = _value; return; case ORDER_REASON: + #ifndef __MQL__ + case __ORDER_REASON: + #endif reason = (ENUM_ORDER_REASON)_value; return; case ORDER_TICKET: @@ -647,6 +657,9 @@ struct OrderData { return; #ifndef __MQL4__ case ORDER_EXTERNAL_ID: + #ifndef __MQL__ + case __ORDER_EXTERNAL_ID: + #endif ext_id = _value; return; #endif diff --git a/Platform/Platform.enum.h b/Platform/Platform.enum.h index 8c8b75309..c195ba137 100644 --- a/Platform/Platform.enum.h +++ b/Platform/Platform.enum.h @@ -25,7 +25,7 @@ #pragma once #endif -#ifndef __MQL4__ +#ifndef __MQL__ // @note Values differ from the documentation at // https://www.mql5.com/en/docs/matrix/matrix_initialization/matrix_copyticks // @see https://www.mql5.com/en/forum/448933 @@ -42,3 +42,15 @@ enum ENUM_COPY_TICKS { COPY_TICKS_FLAGS = 2097152 }; #endif + +// Platform actions. +enum ENUM_PLATFORM_ACTION { + PLATFORM_ACTION_ADD_EXCHANGE = 1, // Add Exchange + FINAL_ENUM_PLATFORM_ACTION_ENTRY +}; + +// Platform conditions. +enum ENUM_PLATFORM_CONDITION { + PLATFORM_COND_IS_ACTIVE = 1, // Is active + FINAL_ENUM_PLATFORM_CONDITION_ENTRY +}; diff --git a/Platform/Platform.h b/Platform/Platform.h index 3d5fbefa1..2ec428f3b 100644 --- a/Platform/Platform.h +++ b/Platform/Platform.h @@ -28,6 +28,7 @@ #include "Deal.enum.h" #include "Order.struct.h" #include "Platform.define.h" + #include "Platform.enum.h" /** * Extern declarations for C++. @@ -41,16 +42,17 @@ extern int Bars(CONST_REF_TO_SIMPLE(string) _symbol, ENUM_TIMEFRAMES _tf); #endif // Includes. - -/** - * Current platform's static methods. - */ - +#include "../Exchange/Exchange.h" #include "../Indicator/IndicatorData.h" #include "../Indicator/tests/classes/IndicatorTfDummy.h" #include "../Indicators/DrawIndicator.mqh" +#include "../Serializer/Serializer.h" #include "../Std.h" #include "../Storage/Flags.struct.h" +#include "../Task/TaskManager.h" +#include "../Task/Taskable.h" +#include "Platform.enum.h" +#include "Platform.struct.h" #ifdef __MQLBUILD__ #include "../Indicators/Tf/Indi_TfMt.h" @@ -65,7 +67,11 @@ extern int Bars(CONST_REF_TO_SIMPLE(string) _symbol, ENUM_TIMEFRAMES _tf); #endif #include "../Exchange/SymbolInfo/SymbolInfo.struct.static.h" -class Platform { +class Platform : public Taskable { + protected: + DictStruct> exchanges; + PlatformParams pparams; + // Whether Init() was already called. static bool initialized; @@ -99,7 +105,50 @@ class Platform { // Timeframe of the currently ticking indicator. static ENUM_TIMEFRAMES period; + private: + /** + * Sets symbol of the currently ticking indicator. + **/ + static void SetSymbol(string _symbol) { symbol = _symbol; } + + /** + * Sets timeframe of the currently ticking indicator. + **/ + static void SetPeriod(ENUM_TIMEFRAMES _period) { period = _period; } + public: + /** + * Class constructor without parameters. + */ + Platform(){}; + + /** + * Class constructor with parameters. + */ + Platform(PlatformParams &_pparams) : pparams(_pparams){}; + + /** + * Class deconstructor. + */ + ~Platform() {} + + /* Adders */ + + /** + * Adds Exchange instance to the list. + */ + void ExchangeAdd(Exchange *_Exchange, int _id = 0) { + Ref _ref = _Exchange; + exchanges.Set(_id, _ref); + } + + /** + * Adds Exchange instance to the list. + */ + void ExchangeAdd(ExchangeParams &_eparams) { ExchangeAdd(new Exchange(_eparams)); } + + /* Static methods */ + /** * Initializes platform. */ @@ -112,6 +161,26 @@ class Platform { initialized = true; } + /** + * When testing code inside the OnInit() method symbol and tf may be + * undefined. This is a way to solve that problem. Use only for + * testing! + */ + static void SetSymbolTfForTesting(string _symbol, ENUM_TIMEFRAMES _tf) { + if (_symbol == PLATFORM_WRONG_SYMBOL) { + Print("Error: SetSymbolTfForTesting() requires valid symbol. Passed \"", _symbol, "\"."); + DebugBreak(); + } + + if (_tf == PERIOD_CURRENT || _tf == PLATFORM_WRONG_TIMEFRAME) { + Print("Error: SetSymbolTfForTesting() requires valid time-frame. Passed \"", EnumToString(_tf), "\"."); + DebugBreak(); + } + + symbol = _symbol; + period = _tf; + } + /** * Returns global tick index. */ @@ -172,6 +241,11 @@ class Platform { ++global_tick_index; } + /** + * Checks whether previous Tick() performed a tick or not. + */ + static bool HadTick() { return last_tick_result; } + /** * Called by indicators' OnCalculate() method in order to prepare history via * IndicatorData::EmitHistory() and to call Tick() for each OnCalculate() @@ -486,16 +560,83 @@ class Platform { return 2; } - private: + /* Taskable methods */ + /** - * Sets symbol of the currently ticking indicator. - **/ - static void SetSymbol(string _symbol) { symbol = _symbol; } + * Checks a condition. + */ + bool Check(const TaskConditionEntry &_entry) override { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + SetUserError(ERR_INVALID_PARAMETER); + } + return _result; + } /** - * Sets timeframe of the currently ticking indicator. - **/ - static void SetPeriod(ENUM_TIMEFRAMES _period) { period = _period; } + * Gets a data param entry. + */ + DataParamEntry Get(const TaskGetterEntry &_entry) override { + DataParamEntry _result; + switch (_entry.GetId()) { + default: + SetUserError(ERR_INVALID_PARAMETER); + } + return _result; + } + + /** + * Runs an action. + */ + bool Run(const TaskActionEntry &_entry) override { + bool _result = true; + switch (_entry.GetId()) { + case PLATFORM_ACTION_ADD_EXCHANGE: + if (!_entry.HasArgs()) { + ExchangeAdd(new Exchange()); + } else { + ExchangeParams _eparams(_entry.GetArg(0).ToString()); + Ref _exchange1_ref = new Exchange(_eparams); + exchanges.Set(_eparams.Get(STRUCT_ENUM(ExchangeParams, EXCHANGE_PARAM_ID)), _exchange1_ref); + } + break; + default: + _result = false; + SetUserError(ERR_INVALID_PARAMETER); + } + return _result; + } + + /** + * Sets an entry value. + */ + bool Set(const TaskSetterEntry &_entry, const DataParamEntry &_entry_value) override { + bool _result = true; + switch (_entry.GetId()) { + default: + _result = false; + SetUserError(ERR_INVALID_PARAMETER); + } + return _result; + } + + /* Serializers */ + + /** + * Returns serialized representation of the object instance. + */ + SerializerNodeType Serialize(Serializer &_s) { + _s.PassStruct(THIS_REF, "params", pparams); + //_s.PassStruct(THIS_REF, "exchanges", exchanges); + return SerializerNodeObject; + } + + /** + * Returns textual representation of the object instance. + */ + const string ToString() override { return SerializerConverter::FromObject(THIS_REF).ToString(); } }; bool Platform::initialized = false; diff --git a/Platform/Platform.struct.h b/Platform/Platform.struct.h new file mode 100644 index 000000000..15fd1af9b --- /dev/null +++ b/Platform/Platform.struct.h @@ -0,0 +1,92 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/** + * @file + * Includes Platform's structs. + */ + +#ifndef __MQL__ + // Allows the preprocessor to include a header file when it is needed. + #pragma once +#endif + +// Includes. +#include "../Serializer/SerializerNode.enum.h" + +/* Defines struct for Platform parameters. */ +struct PlatformParams { + private: + int id; + string name; + + public: + // Enumeration of platform parameters. + enum ENUM_PLATFORM_PARAM { + PLATFORM_PARAM_ID = 1, // ID + PLATFORM_PARAM_NAME, // Name + FINAL_ENUM_PLATFORM_PARAM_ENTRY + }; +#define ENUM_PLATFORM_PARAM STRUCT_ENUM(PlatformParams, ENUM_PLATFORM_PARAM) + public: + // Constructors. + PlatformParams() {} + PlatformParams(const PlatformParams &_eparams) { THIS_REF = _eparams; } + PlatformParams(string _entry) { SerializerConverter::FromString(_entry).ToStruct(THIS_REF); } + // Getters. + template + T Get(ENUM_PLATFORM_PARAM _param) { + T _out; + switch (_param) { + case PLATFORM_PARAM_ID: + return (T)id; + case PLATFORM_PARAM_NAME: + ConvertBasic::Convert(name, _out); + return _out; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + return WRONG_VALUE; + } + // Setters. + template + void Set(ENUM_PLATFORM_PARAM _param, T _value) { + switch (_param) { + case PLATFORM_PARAM_ID: + ConvertBasic::Convert(_value, id); + return; + case PLATFORM_PARAM_NAME: + ConvertBasic::Convert(_value, name); + return; + default: + break; + } + SetUserError(ERR_INVALID_PARAMETER); + } + // Serializers. + SerializerNodeType Serialize(Serializer &s) { + s.Pass(THIS_REF, "id", id); + s.Pass(THIS_REF, "name", name); + return SerializerNodeObject; + } +}; diff --git a/Platform/Plot.h b/Platform/Plot.h index 969d2b9c5..c1c5154e1 100644 --- a/Platform/Plot.h +++ b/Platform/Plot.h @@ -291,7 +291,7 @@ class Plot : public Object { * Plot a vertical line. */ bool DrawVLine(string oname, datetime tm) { - bool result = Plot::ObjectCreate(NULL, oname, OBJ_VLINE, 0, tm, 0); + bool result = Plot::ObjectCreate(0, oname, OBJ_VLINE, 0, tm, 0); if (!result) PrintFormat("%(): Can't create vertical line! code #", __FUNCTION__, GetLastError()); return (result); } @@ -300,7 +300,7 @@ class Plot : public Object { * Plot a horizontal line. */ bool DrawHLine(string oname, double value) { - bool result = Plot::ObjectCreate(NULL, oname, OBJ_HLINE, 0, 0, value); + bool result = Plot::ObjectCreate(0, oname, OBJ_HLINE, 0, 0, value); if (!result) PrintFormat("%(): Can't create horizontal line! code #", __FUNCTION__, GetLastError()); return (result); } @@ -309,7 +309,7 @@ class Plot : public Object { * Delete a vertical line. */ bool DeleteVertLine(string oname) { - bool result = Plot::ObjectDelete(NULL, oname); + bool result = Plot::ObjectDelete(0, oname); if (!result) PrintFormat("%(): Can't delete vertical line! code #", __FUNCTION__, GetLastError()); return (result); } diff --git a/Platform/README.md b/Platform/README.md new file mode 100644 index 000000000..610ac2115 --- /dev/null +++ b/Platform/README.md @@ -0,0 +1,9 @@ +# Exchange + +## Classes + +```mermaid +classDiagram + Taskable <|-- Platform + Platform: Exchange[] +``` diff --git a/Platform/Terminal.define.h b/Platform/Terminal.define.h index 61ef792c3..c2ac1a0d5 100644 --- a/Platform/Terminal.define.h +++ b/Platform/Terminal.define.h @@ -352,7 +352,9 @@ #define ERR_INVALID_STOPS 130 #define ERR_INVALID_TRADE_VOLUME 131 #define ERR_MARKET_CLOSED 132 -//#define ERR_TRADE_DISABLED 133 +#ifndef __MQL__ +#define ERR_TRADE_DISABLED 133 // Already defined in MQL4. +#endif #define ERR_NOT_ENOUGH_MONEY 134 #define ERR_PRICE_CHANGED 135 #define ERR_OFF_QUOTES 136 diff --git a/Platform/Web/tests/Makefile b/Platform/Web/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Platform/Web/tests/Makefile +++ b/Platform/Web/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Platform/Web/tests/Web.test.cpp b/Platform/Web/tests/Web.test.cpp index 66e9901f0..278423a0a 100644 --- a/Platform/Web/tests/Web.test.cpp +++ b/Platform/Web/tests/Web.test.cpp @@ -50,7 +50,7 @@ extern int WebRequest(const string method, // HTTP method ); // Includes. -#include "../../Platform/Platform.h" +#include "../../Platform.h" #include "../Web.h" int main(int argc, char **argv) { diff --git a/Platform/tests/Makefile b/Platform/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Platform/tests/Makefile +++ b/Platform/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Platform/tests/Platform.test.mq5 b/Platform/tests/Platform.test.mq5 index f7df7c7a6..e74c0fc50 100644 --- a/Platform/tests/Platform.test.mq5 +++ b/Platform/tests/Platform.test.mq5 @@ -28,12 +28,30 @@ #include "../../Test.mqh" #include "../Platform.h" +// Test Platform tasks. +bool TestPlatform01() { + bool _result = true; + // Initialize a dummy Exchange instance. + PlatformParams _pparams("{\"name\": \"Platform\"}"); + Ref platform = new Platform(_pparams); + // Add exchange01 via task. + TaskActionEntry _task_add_ex_01(PLATFORM_ACTION_ADD_EXCHANGE); + platform.Ptr().Run(_task_add_ex_01); + // Add exchange02 from JSON via task. + TaskActionEntry _task_add_ex_02(PLATFORM_ACTION_ADD_EXCHANGE); + DataParamEntry _ex_02_entry = "{\"id\": 1, \"name\": \"exchange02\"}"; + _task_add_ex_02.ArgAdd(_ex_02_entry); + platform.Ptr().Run(_task_add_ex_02); + Print(platform.Ptr().ToString()); + return _result; +} + /** * Implements OnInit(). */ int OnInit() { bool _result = true; - // @todo: Write some tests. + assertTrueOrFail(TestPlatform01(), "Fail!"); return _result && GetLastError() == 0 ? INIT_SUCCEEDED : INIT_FAILED; } diff --git a/Refs.struct.h b/Refs.struct.h index e238323c8..3f421fb03 100644 --- a/Refs.struct.h +++ b/Refs.struct.h @@ -31,6 +31,7 @@ #endif #include "Refs.rc.h" +#include "Serializer/SerializerNode.enum.h" #include "Std.h" #ifdef EMSCRIPTEN @@ -38,7 +39,8 @@ #endif class Dynamic; -// Forward class declaration. +// Forward declarations. +class Serializer; template struct WeakRef; @@ -282,6 +284,11 @@ struct Ref { return ptr_object PTR_DEREF ToString(); } + +#ifdef __MQL__ + template <> +#endif + SerializerNodeType Serialize(Serializer& s); }; #ifdef __cplusplus diff --git a/Serializer/Serializer.h b/Serializer/Serializer.h index 359e0332d..764f0db1e 100644 --- a/Serializer/Serializer.h +++ b/Serializer/Serializer.h @@ -461,7 +461,7 @@ class Serializer { * Returns next structure or structure by given key. */ template - X REF_CPP Struct(string key = "") { + X Struct(string key = "") { X value; PassStruct(THIS_REF, key, value); return value; diff --git a/Serializer/Serializer.ref.h b/Serializer/Serializer.ref.h new file mode 100644 index 000000000..06a04388a --- /dev/null +++ b/Serializer/Serializer.ref.h @@ -0,0 +1,49 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +// Prevents processing this includes file for the second time. +#ifndef __MQL__ +#pragma once +#endif + +#include "../Refs.struct.h" + +template +#ifdef __MQL__ +template <> +SerializerNodeType Ref::Serialize(Serializer& s) { +#else +SerializerNodeType Ref::Serialize(Serializer& s) { +#endif + if (s.IsWriting()) { + if (Ptr() == nullptr) { + // Missing object! + Alert("Error: Ref serialization is supported only for non-null references!"); + DebugBreak(); + return SerializerNodeObject; + } + return Ptr() PTR_DEREF Serialize(s); + } else { + // Reading. + return Ptr() PTR_DEREF Serialize(s); + } +} diff --git a/Serializer/SerializerConverter.h b/Serializer/SerializerConverter.h index 31e013779..52827e456 100644 --- a/Serializer/SerializerConverter.h +++ b/Serializer/SerializerConverter.h @@ -35,7 +35,7 @@ class SerializerNode; #include "SerializerDict.h" #include "SerializerNode.h" -#ifdef __debug_verbose__ +#ifdef __debug_serializer__ #include "SerializerJson.h" #endif @@ -68,7 +68,7 @@ class SerializerConverter { _serializer.FreeRootNodeOwnership(); _serializer.PassObject(_value, "", _value, SERIALIZER_FIELD_FLAG_VISIBLE); SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); -#ifdef __debug_verbose__ +#ifdef __debug_serializer__ Print("FromObject(): serializer flags: ", serializer_flags); Print("FromObject(): result: ", _serializer.GetRoot() != NULL ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) @@ -83,7 +83,7 @@ class SerializerConverter { _serializer.FreeRootNodeOwnership(); _serializer.PassObject(_value, "", _value, SERIALIZER_FIELD_FLAG_VISIBLE); SerializerConverter _converter(_serializer.GetRoot(), serializer_flags); -#ifdef __debug_verbose__ +#ifdef __debug_serializer__ Print("FromObject(): serializer flags: ", serializer_flags); Print("FromObject(): result: ", _serializer.GetRoot() != NULL ? _serializer.GetRoot() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) @@ -115,7 +115,7 @@ class SerializerConverter { template static SerializerConverter FromString(string arg) { SerializerConverter _converter(((C*)NULL)PTR_DEREF Parse(arg), 0); -#ifdef __debug_verbose__ +#ifdef __debug_serializer__ Print("FromString(): result: ", _converter.Node() != NULL ? _converter.Node() PTR_DEREF ToString(SERIALIZER_JSON_NO_WHITESPACES) : "NULL"); #endif diff --git a/Serializer/SerializerCsv.h b/Serializer/SerializerCsv.h index 6db82e328..d82746379 100644 --- a/Serializer/SerializerCsv.h +++ b/Serializer/SerializerCsv.h @@ -21,8 +21,8 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once #endif // Includes. @@ -115,7 +115,7 @@ class SerializerCsv { } } -#ifdef __debug_verbose__ +#ifdef __debug_serializer__ Print("Stub: ", _stub PTR_DEREF Node() PTR_DEREF ToString()); Print("Data: ", _root PTR_DEREF ToString()); Print("Size: ", _num_columns, " x ", _num_rows); @@ -180,7 +180,16 @@ class SerializerCsv { if (_child PTR_DEREF IsContainer()) { ExtractColumns(_child, _titles, _column_types, _flags, _column); } else if (_child PTR_DEREF HasKey()) { - _titles PTR_DEREF Set(_column++, 0, _child PTR_DEREF Key()); + if (_column_types != NULL) { + // Filling columns types here as if there's no data then column types will be unknown. + if (_child PTR_DEREF GetValueParam() == NULL) { + Alert("Error: Expected value here! Stub is probably initialized without proper structure."); + DebugBreak(); + } + _column_types PTR_DEREF Set(_column, 0, _child PTR_DEREF GetValueParam() PTR_DEREF GetType()); + } + _titles PTR_DEREF Set(_column, 0, _child PTR_DEREF Key()); + _column++; } } } diff --git a/Serializer/SerializerJson.h b/Serializer/SerializerJson.h index 6e841fb31..776a6818d 100644 --- a/Serializer/SerializerJson.h +++ b/Serializer/SerializerJson.h @@ -145,7 +145,8 @@ class SerializerJson { else if (StringGetCharacter(data, 0) == '[') ; else { - return GracefulReturn("Failed to parse JSON. It must start with either \"{\" or \"[\".", 0, NULL, NULL); + return GracefulReturn( + string(__FUNCTION__) + "(): Failed to parse JSON. It must start with either \"{\" or \"[\".", 0, NULL, NULL); } SerializerNode* root = NULL; @@ -182,7 +183,7 @@ class SerializerJson { extracted = ExtractString(data, i + 1); if (extracted == "") { - return GracefulReturn("Unexpected end of file when parsing string", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Unexpected end of file when parsing string", i, root, key); } if (expectingKey) { key = SerializerNodeParam::FromString(extracted); @@ -193,31 +194,33 @@ class SerializerJson { ? SerializerNodeObjectProperty : SerializerNodeArrayItem, current, key, SerializerNodeParam::FromString(extracted)))); + // Key is in use so we don't want to delete it. + key = NULL; -#ifdef __debug__ - Print("SerializerJson: Value \"" + extracted + "\" for key " + +#ifdef __debug_serializer__ + Print(string(__FUNCTION__) + "(): Value \"" + extracted + "\" for key " + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif expectingValue = false; } else { - return GracefulReturn("Unexpected '\"' symbol", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Unexpected '\"' symbol", i, root, key); } // Skipping double quotes. i += StringLen(extracted) + 1; } else if (expectingSemicolon) { if (ch != ':') { - return GracefulReturn("Expected semicolon", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Expected semicolon", i, root, key); } expectingSemicolon = false; expectingValue = true; } else if (ch == '{') { if (expectingKey) { - return GracefulReturn("Cannot use object as a key", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Cannot use object as a key", i, root, key); } -#ifdef __debug__ +#ifdef __debug_serializer__ Print("SerializerJson: Entering object for key " + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif @@ -232,14 +235,15 @@ class SerializerJson { expectingValue = false; expectingKey = ch2 != '}'; + // Key is in use so we don't want to delete it. key = NULL; } else if (ch == '}') { if (expectingKey || expectingValue || PTR_ATTRIB(current, GetType()) != SerializerNodeObject) { - return GracefulReturn("Unexpected end of object", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Unexpected end of object", i, root, key); } -#ifdef __debug__ - Print("SerializerJson: Leaving object for key " + +#ifdef __debug_serializer__ + Print(string(__FUNCTION__) + "(): Leaving object for key " + (current != NULL && current PTR_DEREF GetKeyParam() != NULL ? ("\"" + current PTR_DEREF GetKeyParam() PTR_DEREF ToString() + "\"") : "")); @@ -248,13 +252,13 @@ class SerializerJson { current = PTR_ATTRIB(current, GetParent()); expectingValue = false; } else if (ch == '[') { -#ifdef __debug__ - Print("SerializerJson: Entering list for key " + +#ifdef __debug_serializer__ + Print(string(__FUNCTION__) + "(): Entering list for key " + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif if (expectingKey) { - return GracefulReturn("Cannot use array as a key", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Cannot use array as a key", i, root, key); } node = new SerializerNode(SerializerNodeArray, current, key); @@ -265,32 +269,33 @@ class SerializerJson { current = node; expectingValue = ch2 != ']'; + // Key is in use so we don't want to delete it. key = NULL; } else if (ch == ']') { -#ifdef __debug__ - Print("SerializerJson: Leaving list for key " + +#ifdef __debug_serializer__ + Print(string(__FUNCTION__) + "(): Leaving list for key " + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif if (expectingKey || expectingValue || PTR_ATTRIB(current, GetType()) != SerializerNodeArray) { - return GracefulReturn("Unexpected end of array", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Unexpected end of array", i, root, key); } current = PTR_ATTRIB(current, GetParent()); expectingValue = false; } else if (ch >= '0' && ch <= '9') { if (!expectingValue) { - return GracefulReturn("Unexpected numeric value", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Unexpected numeric value", i, root, key); } if (!ExtractNumber(data, i, extracted)) { - return GracefulReturn("Cannot parse numeric value", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Cannot parse numeric value", i, root, key); } value = StringFind(extracted, ".") != -1 ? SerializerNodeParam::FromValue(StringToDouble(extracted)) : SerializerNodeParam::FromValue(StringToInteger(extracted)); -#ifdef __debug__ - Print("SerializerJson: Value " + value PTR_DEREF AsString() + " for key " + +#ifdef __debug_serializer__ + Print(string(__FUNCTION__) + "(): Value " + value PTR_DEREF AsString() + " for key " + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif @@ -303,16 +308,16 @@ class SerializerJson { // Skipping value. i += StringLen(extracted) - 1; - // We don't want to delete it twice. + // Key is in use so we don't want to delete it. key = NULL; } else if (ch == 't' || ch == 'f') { // Assuming true/false. value = SerializerNodeParam::FromValue(ch == 't' ? true : false); -#ifdef __debug__ - Print(string("SerializerJson: Value ") + (value PTR_DEREF ToBool() ? "true" : "false") + " for key " + - (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); +#ifdef __debug_serializer__ + Print(string(string(__FUNCTION__) + "(): Value ") + (value PTR_DEREF ToBool() ? "true" : "false") + + " for key " + (key != NULL ? ("\"" + key PTR_DEREF ToString() + "\"") : "")); #endif // Skipping value. @@ -324,11 +329,11 @@ class SerializerJson { current, key, value))); expectingValue = false; - // We don't want to delete it twice. + // Key is in use so we don't want to delete it. key = NULL; } else if (ch == ',') { if (expectingKey || expectingValue || expectingSemicolon) { - return GracefulReturn("Unexpected comma", i, root, key); + return GracefulReturn(string(__FUNCTION__) + "(): Unexpected comma", i, root, key); } if (PTR_ATTRIB(current, GetType()) == SerializerNodeObject) @@ -338,7 +343,9 @@ class SerializerJson { } } - if (key) delete key; + if (key) { + delete key; + } return root; } diff --git a/Serializer/SerializerNodeParam.h b/Serializer/SerializerNodeParam.h index 1ae965e89..e96f8c705 100644 --- a/Serializer/SerializerNodeParam.h +++ b/Serializer/SerializerNodeParam.h @@ -198,7 +198,7 @@ class SerializerNodeParam { _fp_precision); } -#ifdef __debug__ +#ifdef __debug_serializer__ PrintFormat("%s: Error: SerializerNodeParam.AsString() called for an unknown value type: %d!", __FUNCTION__, _type); #endif return ""; @@ -345,7 +345,7 @@ SerializerNodeParam* SerializerNodeParam::FromLong(int64 value) { /** * Returns new SerializerNodeParam object from given source value. */ -SerializerNodeParam* SerializerNodeParam::FromLong(uint64 value) { return FromLong((uint64)value); } +SerializerNodeParam* SerializerNodeParam::FromLong(uint64 value) { return FromLong((int64)value); } /** * Returns new SerializerNodeParam object from given source value. diff --git a/Serializer/SerializerSqlite.h b/Serializer/SerializerSqlite.h index 0204ee589..0748c6e00 100644 --- a/Serializer/SerializerSqlite.h +++ b/Serializer/SerializerSqlite.h @@ -56,7 +56,7 @@ class SerializerSqlite { string _csv = SerializerCsv::Stringify(source.root_node, _stringify_flags | SERIALIZER_CSV_INCLUDE_TITLES, _stub, &_matrix_out, &_column_types); -#ifdef __debug__ +#ifdef __debug_serializer__ Print("SerializerSqlite: Parsing CSV input:\n", _csv); #endif diff --git a/Serializer/tests/Makefile b/Serializer/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Serializer/tests/Makefile +++ b/Serializer/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Serializer/tests/Serializable.test.cpp b/Serializer/tests/Serializable.test.cpp index ad60d7be0..220e8048f 100644 --- a/Serializer/tests/Serializable.test.cpp +++ b/Serializer/tests/Serializable.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of Serializable class. - */ - -// Includes. -#include "../Serializable.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of Serializable class. + */ + +// Includes. +#include "../Serializable.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/Serializer.test.cpp b/Serializer/tests/Serializer.test.cpp index cd6cad5f9..50b09bbf4 100644 --- a/Serializer/tests/Serializer.test.cpp +++ b/Serializer/tests/Serializer.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of Serializer class. - */ - -// Includes. -#include "../Serializer.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of Serializer class. + */ + +// Includes. +#include "../Serializer.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/Serializer.test.mq5 b/Serializer/tests/Serializer.test.mq5 index d6e5e1cb0..d47f376ef 100644 --- a/Serializer/tests/Serializer.test.mq5 +++ b/Serializer/tests/Serializer.test.mq5 @@ -19,7 +19,7 @@ * along with this program. If not, see . */ -#define __debug__ +#define __debug_serializer__ /** * @file @@ -27,12 +27,12 @@ */ // Includes. -#include "../../Storage/Dict/Buffer/BufferStruct.h" -#include "../../Platform/Chart/Chart.h" #include "../../Config.mqh" +#include "../../Platform/Chart/Chart.h" #include "../../Storage/Data.define.h" #include "../../Storage/Data.struct.h" #include "../../Storage/Data.struct.serialize.h" +#include "../../Storage/Dict/Buffer/BufferStruct.h" #include "../../Storage/Dict/DictStruct.h" #include "../../Test.mqh" #include "../Serializer.h" diff --git a/Serializer/tests/SerializerBinary.test.cpp b/Serializer/tests/SerializerBinary.test.cpp index 1b784bab3..6348f4455 100644 --- a/Serializer/tests/SerializerBinary.test.cpp +++ b/Serializer/tests/SerializerBinary.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerBinary class. - */ - -// Includes. -#include "../SerializerBinary.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerBinary class. + */ + +// Includes. +#include "../SerializerBinary.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerConversions.test.cpp b/Serializer/tests/SerializerConversions.test.cpp index 0b06b3943..1bc2cfbb0 100644 --- a/Serializer/tests/SerializerConversions.test.cpp +++ b/Serializer/tests/SerializerConversions.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerConversions class. - */ - -// Includes. -#include "../SerializerConversions.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerConversions class. + */ + +// Includes. +#include "../SerializerConversions.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerConverter.test.cpp b/Serializer/tests/SerializerConverter.test.cpp index b5156758b..85dac8db3 100644 --- a/Serializer/tests/SerializerConverter.test.cpp +++ b/Serializer/tests/SerializerConverter.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerConverter class. - */ - -// Includes. -#include "../SerializerConverter.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerConverter class. + */ + +// Includes. +#include "../SerializerConverter.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerCsv.test.cpp b/Serializer/tests/SerializerCsv.test.cpp index 73175c8b9..49487c342 100644 --- a/Serializer/tests/SerializerCsv.test.cpp +++ b/Serializer/tests/SerializerCsv.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2024, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerCsv class. - */ - -// Includes. -#include "../SerializerCsv.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2024, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerCsv class. + */ + +// Includes. +#include "../SerializerCsv.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerDict.test.cpp b/Serializer/tests/SerializerDict.test.cpp index 68b01a7d4..a79d237e3 100644 --- a/Serializer/tests/SerializerDict.test.cpp +++ b/Serializer/tests/SerializerDict.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerDict class. - */ - -// Includes. -#include "../SerializerDict.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerDict class. + */ + +// Includes. +#include "../SerializerDict.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerJson.test.cpp b/Serializer/tests/SerializerJson.test.cpp index bb3975a0e..5a15a5676 100644 --- a/Serializer/tests/SerializerJson.test.cpp +++ b/Serializer/tests/SerializerJson.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerJson class. - */ - -// Includes. -#include "../SerializerJson.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerJson class. + */ + +// Includes. +#include "../SerializerJson.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerNode.test.cpp b/Serializer/tests/SerializerNode.test.cpp index cc4f28237..f49862163 100644 --- a/Serializer/tests/SerializerNode.test.cpp +++ b/Serializer/tests/SerializerNode.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerNode class. - */ - -// Includes. -#include "../SerializerNode.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerNode class. + */ + +// Includes. +#include "../SerializerNode.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerNodeIterator.test.cpp b/Serializer/tests/SerializerNodeIterator.test.cpp index f11e9ee51..0df95521c 100644 --- a/Serializer/tests/SerializerNodeIterator.test.cpp +++ b/Serializer/tests/SerializerNodeIterator.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerNodeIterator class. - */ - -// Includes. -#include "../SerializerNodeIterator.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerNodeIterator class. + */ + +// Includes. +#include "../SerializerNodeIterator.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerNodeParam.test.cpp b/Serializer/tests/SerializerNodeParam.test.cpp index de4601e87..de1b64317 100644 --- a/Serializer/tests/SerializerNodeParam.test.cpp +++ b/Serializer/tests/SerializerNodeParam.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerNodeParam class. - */ - -// Includes. -#include "../SerializerNodeParam.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerNodeParam class. + */ + +// Includes. +#include "../SerializerNodeParam.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerObject.test.cpp b/Serializer/tests/SerializerObject.test.cpp index 66bef2d08..f8d5b0586 100644 --- a/Serializer/tests/SerializerObject.test.cpp +++ b/Serializer/tests/SerializerObject.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerObject class. - */ - -// Includes. -#include "../SerializerObject.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerObject class. + */ + +// Includes. +#include "../SerializerObject.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Serializer/tests/SerializerSqlite.test.cpp b/Serializer/tests/SerializerSqlite.test.cpp index 13f4002e8..982d6fb8a 100644 --- a/Serializer/tests/SerializerSqlite.test.cpp +++ b/Serializer/tests/SerializerSqlite.test.cpp @@ -1,36 +1,36 @@ -//+------------------------------------------------------------------+ -//| EA31337 framework | -//| Copyright 2016-2023, EA31337 Ltd | -//| https://ea31337.github.io | -//+------------------------------------------------------------------+ - -/* - * This file is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -/** - * @file - * Test C++ compilation of SerializerSqlite class. - */ - -// Includes. -#include "../SerializerSqlite.h" - -#include "../../Platform/Platform.h" - -int main(int argc, char **argv) { - // @todo - - return 0; -} +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of SerializerSqlite class. + */ + +// Includes. +#include "../SerializerSqlite.h" + +#include "../../Platform/Platform.h" + +int main(int argc, char **argv) { + // @todo + + return 0; +} diff --git a/Std.h b/Std.h index 789ec31eb..c4a5d6ce1 100644 --- a/Std.h +++ b/Std.h @@ -387,15 +387,19 @@ class InvalidEnumValue { #endif static const T value() { - return (T)INT_MAX; +#ifdef __MQL__ + return (T)NULL; +#else + return std::numeric_limits::max(); +#endif } }; #ifndef __MQL__ struct _WRONG_VALUE { template - operator T() { - return (T)-1; + operator T() const { + return std::numeric_limits::max(); } } WRONG_VALUE; @@ -405,10 +409,9 @@ const string _empty_string = ""; // Converter of NULL_VALUE into expected type. e.g., "int x = NULL_VALUE" will end up with "x = 0". struct _NULL_VALUE { template - explicit operator T() const { - return (T)0; + operator T() const { + return std::numeric_limits::max(); } - } NULL_VALUE; /** diff --git a/Storage/Cache/tests/Makefile b/Storage/Cache/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Storage/Cache/tests/Makefile +++ b/Storage/Cache/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Storage/Data.struct.h b/Storage/Data.struct.h index eccdcb798..7a85f266e 100644 --- a/Storage/Data.struct.h +++ b/Storage/Data.struct.h @@ -36,6 +36,7 @@ struct MqlParam; struct MqlRates; // Includes. +#include "../Convert.extern.h" #include "../Serializer/Serializer.enum.h" #include "../Serializer/SerializerNode.enum.h" #include "../Std.h" @@ -217,9 +218,30 @@ struct DataParamEntry : public MqlParam { /* Getters */ + /** + * Gets a string of the given type. + */ + string ToString() { + switch (type) { + case TYPE_CHAR: + case TYPE_STRING: + case TYPE_UCHAR: + return string_value; + case TYPE_DOUBLE: + case TYPE_FLOAT: + return DoubleToString(double_value); + default: + case TYPE_BOOL: + case TYPE_INT: + case TYPE_LONG: + case TYPE_UINT: + case TYPE_ULONG: + return IntegerToString(integer_value); + } + } + /** * Gets a value of the given type. - * */ template T ToValue() { @@ -307,10 +329,14 @@ struct DataParamEntry : public MqlParam { switch (param.type) { case TYPE_BOOL: return param.integer_value ? 1 : 0; + case TYPE_COLOR: + case TYPE_DATETIME: case TYPE_INT: case TYPE_LONG: + case TYPE_SHORT: case TYPE_UINT: case TYPE_ULONG: + case TYPE_USHORT: return (double)param.integer_value; case TYPE_DOUBLE: case TYPE_FLOAT: @@ -319,11 +345,6 @@ struct DataParamEntry : public MqlParam { case TYPE_STRING: case TYPE_UCHAR: return ::StringToDouble(param.string_value); - case TYPE_COLOR: - case TYPE_DATETIME: - case TYPE_SHORT: - case TYPE_USHORT: - return DBL_MIN; } return DBL_MIN; } @@ -342,6 +363,7 @@ struct DataParamEntry : public MqlParam { case TYPE_UINT: case TYPE_ULONG: case TYPE_SHORT: + case TYPE_USHORT: return param.integer_value; case TYPE_DOUBLE: case TYPE_FLOAT: @@ -351,12 +373,38 @@ struct DataParamEntry : public MqlParam { case TYPE_STRING: case TYPE_UCHAR: return ::StringToInteger(param.string_value); - case TYPE_USHORT: - return INT_MIN; } return INT_MIN; } + /** + * Converts MqlParam struct to string. + * + */ + static string ToString(MqlParam ¶m) { + switch (param.type) { + case TYPE_BOOL: + return param.integer_value ? "true" : "false"; + case TYPE_DATETIME: + case TYPE_INT: + case TYPE_LONG: + case TYPE_UINT: + case TYPE_ULONG: + case TYPE_SHORT: + case TYPE_USHORT: + return IntegerToString(param.integer_value); + case TYPE_DOUBLE: + case TYPE_FLOAT: + return DoubleToString(param.double_value); + case TYPE_CHAR: + case TYPE_COLOR: + case TYPE_STRING: + case TYPE_UCHAR: + return param.string_value; + } + return ""; + } + /* Serializers */ /** diff --git a/Storage/DateTime.extern.h b/Storage/DateTime.extern.h index ebd99b875..1c7b14554 100644 --- a/Storage/DateTime.extern.h +++ b/Storage/DateTime.extern.h @@ -55,14 +55,22 @@ class datetime { operator int64() const { return dt; } }; -extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, - ARRAY_REF(datetime, time_array)); +int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, int start_pos, int count, ARRAY_REF(datetime, time_array)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, datetime start_time, int count, - ARRAY_REF(datetime, time_array)); + ARRAY_REF(datetime, time_array)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} extern int CopyTime(string symbol_name, ENUM_TIMEFRAMES timeframe, datetime start_time, datetime stop_time, - ARRAY_REF(datetime, time_array)); + ARRAY_REF(datetime, time_array)) { + Print("Not yet implemented: ", __FUNCTION__, " returns 0."); + return 0; +} extern datetime StructToTime(MqlDateTime& dt_struct); extern bool TimeToStruct(datetime dt, MqlDateTime& dt_struct); diff --git a/Storage/Dict/Buffer/BufferCandle.h b/Storage/Dict/Buffer/BufferCandle.h index 1126963b8..eb0406f66 100644 --- a/Storage/Dict/Buffer/BufferCandle.h +++ b/Storage/Dict/Buffer/BufferCandle.h @@ -26,7 +26,7 @@ #endif // Includes. -#include "../../../Candle.struct.h" +#include "../../../Platform/Chart/Candle.struct.h" #include "../../../Serializer/SerializerConverter.h" #include "../../../Serializer/SerializerJson.h" #include "BufferStruct.h" diff --git a/Storage/Dict/Buffer/tests/Makefile b/Storage/Dict/Buffer/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Storage/Dict/Buffer/tests/Makefile +++ b/Storage/Dict/Buffer/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Storage/Dict/DictStruct.h b/Storage/Dict/DictStruct.h index c4a4efa3a..0b83995ec 100644 --- a/Storage/Dict/DictStruct.h +++ b/Storage/Dict/DictStruct.h @@ -511,7 +511,8 @@ class DictStruct : public DictBase { // Note that we're retrieving value by a key (as we are in an // object!). - Set(key, s.Struct(i.Key())); + V _value = s.Struct(i.Key()); + Set(key, _value); } else { Push(s.Struct()); } diff --git a/Storage/Dict/tests/Makefile b/Storage/Dict/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Storage/Dict/tests/Makefile +++ b/Storage/Dict/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Instances.h b/Storage/Instances.h similarity index 92% rename from Instances.h rename to Storage/Instances.h index 548aaa015..726bf072d 100644 --- a/Instances.h +++ b/Storage/Instances.h @@ -34,8 +34,8 @@ #ifndef INSTANCES_H #define INSTANCES_H -#include "Storage/Dict/Dict.h" -#include "Util.h" +#include "Dict/Dict.h" +#include "../Util.h" template class Instances { @@ -52,7 +52,8 @@ template #ifdef __MQL__ T* Instances::instances[]; #else -T* Instances::instances[]; +//T* Instances::instances[]; +ARRAY(T*, Instances::instances); #endif -#endif // INSTANCES_MQH +#endif // INSTANCES_H diff --git a/Storage/State.struct.h b/Storage/State.struct.h new file mode 100644 index 000000000..a1ea8757e --- /dev/null +++ b/Storage/State.struct.h @@ -0,0 +1,72 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2023, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#ifndef __MQL__ +// Allows the preprocessor to include a header file when it is needed. +#pragma once +#endif + +/** + * State structure. + */ +struct State { + protected: + unsigned int state; // Bitwise value. + public: + // Struct constructor. + State() : state(0) {} + unsigned int GetState() { return state; } + // Struct methods for bitwise operations. + bool Has(unsigned int _state) { return (state & _state) != 0 || state == _state; } + // Checks whether current states has any given states. + bool HasAny(unsigned int _state) { return (state & _state) != 0; } + // Checks whether current states has all given states. + bool HasMulti(unsigned int _state) { return (state & _state) == _state; } + // Adds a single state to the current states. + void Add(unsigned int _state) { state |= _state; } + // Clear all states. + void ClearAll() { state = 0; } + // Clears given state or multiple states from the current states. + void Clear(unsigned int _state) { state &= ~_state; } + void SetState(unsigned int _state, bool _value = true) { + if (_value) { + Add(_state); + } else { + Clear(_state); + } + } + void SetState(unsigned int _state) { state = _state; } + // Static methods. + static bool Compare(unsigned int _state1, unsigned int _state2) { + return (_state2 & _state1) != 0 || _state2 == _state1; + } + // Serializers. + void SerializeStub(int _n1 = 1, int _n2 = 1, int _n3 = 1, int _n4 = 1, int _n5 = 1) {} + SerializerNodeType Serialize(Serializer &_s) { + int _size = sizeof(int) * 8; + for (int i = 0; i < _size; i++) { + int _value = Has(1 << i) ? 1 : 0; + _s.Pass(THIS_REF, IntegerToString(i + 1), _value, SERIALIZER_FIELD_FLAG_DYNAMIC); + } + return SerializerNodeObject; + } +}; diff --git a/Storage/String.extern.h b/Storage/String.extern.h index bd8f3079e..22be3ed8d 100644 --- a/Storage/String.extern.h +++ b/Storage/String.extern.h @@ -21,21 +21,21 @@ */ #ifndef __MQL__ -// Allows the preprocessor to include a header file when it is needed. -#pragma once + // Allows the preprocessor to include a header file when it is needed. + #pragma once -// Includes. -#include + // Includes. + #include -#include -#include -#include -#include -#include + #include + #include + #include + #include + #include -#include "../Math/Math.extern.h" -#include "../Platform/Terminal.define.h" -#include "../Std.h" + #include "../Math/Math.extern.h" + #include "../Platform/Terminal.define.h" + #include "../Std.h" // Define external global functions. double StringToDouble(string value) { return std::stod(value); } @@ -121,8 +121,6 @@ bool StringInit(string& string_var, int new_len = 0, unsigned short character = string CharArrayToString(ARRAY_REF(unsigned char, arr), int start = 0, int count = -1, unsigned int codepage = CP_ACP) { if (count == -1) count = (arr.size() - start); - int _end = MathMin(count - start, arr.size()); - string result; StringInit(result, count); diff --git a/Storage/tests/Instances.test.cpp b/Storage/tests/Instances.test.cpp new file mode 100644 index 000000000..2dc6b3f7a --- /dev/null +++ b/Storage/tests/Instances.test.cpp @@ -0,0 +1,41 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2024, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test C++ compilation of Instances class. + */ + +// Includes. +#include "../Instances.h" + +int main(int argc, char **argv) { + // Create a new object. + // Instances *obj = new Instances(); + + // @todo: Add more tests. + // ... + + // Clean up. + // Instances::Delete(obj); + + return 0; +} diff --git a/Storage/tests/Instances.test.mq4 b/Storage/tests/Instances.test.mq4 new file mode 100644 index 000000000..b5d94b5f1 --- /dev/null +++ b/Storage/tests/Instances.test.mq4 @@ -0,0 +1,28 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2024, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Instances class. + */ + +// Includes. +#include "Instances.test.mq5" diff --git a/Storage/tests/Instances.test.mq5 b/Storage/tests/Instances.test.mq5 new file mode 100644 index 000000000..c46c59ff0 --- /dev/null +++ b/Storage/tests/Instances.test.mq5 @@ -0,0 +1,45 @@ +//+------------------------------------------------------------------+ +//| EA31337 framework | +//| Copyright 2016-2024, EA31337 Ltd | +//| https://ea31337.github.io | +//+------------------------------------------------------------------+ + +/* + * This file is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * @file + * Test functionality of Instances class. + */ + +// Includes. +#include "../../Test.mqh" +#include "../Instances.h" + +/** + * Implements OnInit(). + */ +int OnInit() { + // Create a new object. + // Instances *obj = new Instances(); + + // @todo: Add more tests. + // ... + + // Clean up. + // Instances::Delete(obj); + + return (GetLastError() > 0 ? INIT_FAILED : INIT_SUCCEEDED); +} diff --git a/Storage/tests/Makefile b/Storage/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Storage/tests/Makefile +++ b/Storage/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Strategy.enum.h b/Strategy/Strategy.enum.h similarity index 100% rename from Strategy.enum.h rename to Strategy/Strategy.enum.h diff --git a/Strategy.mqh b/Strategy/Strategy.h similarity index 99% rename from Strategy.mqh rename to Strategy/Strategy.h index 4f51cc261..f397ef318 100644 --- a/Strategy.mqh +++ b/Strategy/Strategy.h @@ -21,25 +21,25 @@ */ // Prevents processing this includes file for the second time. -#ifndef STRATEGY_MQH -#define STRATEGY_MQH +#ifndef STRATEGY_H +#define STRATEGY_H // Forward declaration. class Trade; // Includes. -#include "Indicator/Indicator.h" -#include "Market.mqh" -#include "Math/Math.h" -#include "Storage/Data.struct.h" -#include "Storage/Dict/Dict.h" -#include "Storage/Object.h" -#include "Storage/String.h" +#include "../Indicator/Indicator.h" +#include "../Market.mqh" +#include "../Math/Math.h" +#include "../Storage/Data.struct.h" +#include "../Storage/Dict/Dict.h" +#include "../Storage/Object.h" +#include "../Storage/String.h" #include "Strategy.enum.h" #include "Strategy.struct.h" -#include "Task/TaskManager.h" -#include "Task/Taskable.h" -#include "Trade.mqh" +#include "../Task/TaskManager.h" +#include "../Task/Taskable.h" +#include "../Trade.mqh" // Defines. // Primary inputs. @@ -1285,4 +1285,4 @@ class Strategy : public Taskable { return SerializerNodeObject; } }; -#endif // STRATEGY_MQH +#endif // STRATEGY_H diff --git a/Strategy.struct.h b/Strategy/Strategy.struct.h similarity index 99% rename from Strategy.struct.h rename to Strategy/Strategy.struct.h index 178197aed..74adf6efc 100644 --- a/Strategy.struct.h +++ b/Strategy/Strategy.struct.h @@ -31,10 +31,10 @@ #endif // Includes. -#include "Serializer/Serializer.h" +#include "../Serializer/Serializer.h" #include "Strategy.enum.h" #include "Strategy.struct.pricestop.h" -#include "Task/Task.struct.h" +#include "../Task/Task.struct.h" // Forward class declaration. class Strategy; diff --git a/Strategy.struct.pricestop.h b/Strategy/Strategy.struct.pricestop.h similarity index 99% rename from Strategy.struct.pricestop.h rename to Strategy/Strategy.struct.pricestop.h index 772a3862f..9794e49fd 100644 --- a/Strategy.struct.pricestop.h +++ b/Strategy/Strategy.struct.pricestop.h @@ -35,7 +35,7 @@ struct ChartParams; struct IndicatorParams; // Includes. -#include "Platform/Chart/Chart.struct.h" +#include "../Platform/Chart/Chart.struct.h" /* Structure for strategy price stops. */ struct StrategyPriceStop { diff --git a/Strategy/tests/Makefile b/Strategy/tests/Makefile new file mode 100644 index 000000000..ba14b9322 --- /dev/null +++ b/Strategy/tests/Makefile @@ -0,0 +1,40 @@ +CC := g++ # C++ compiler +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) + +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON + +%.o: %.cpp + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/tests/StrategyTest-RSI.mq4 b/Strategy/tests/Strategy-RSI.test.mq4 similarity index 97% rename from tests/StrategyTest-RSI.mq4 rename to Strategy/tests/Strategy-RSI.test.mq4 index 2517e2405..29b948365 100644 --- a/tests/StrategyTest-RSI.mq4 +++ b/Strategy/tests/Strategy-RSI.test.mq4 @@ -27,4 +27,4 @@ #define __debug__ // Includes. -#include "StrategyTest-RSI.mq5" +#include "Strategy-RSI.test.mq5" diff --git a/tests/StrategyTest-RSI.mq5 b/Strategy/tests/Strategy-RSI.test.mq5 similarity index 94% rename from tests/StrategyTest-RSI.mq5 rename to Strategy/tests/Strategy-RSI.test.mq5 index 0ce6b299b..04bca242e 100644 --- a/tests/StrategyTest-RSI.mq5 +++ b/Strategy/tests/Strategy-RSI.test.mq5 @@ -28,12 +28,12 @@ //#define __debug_verbose__ // Includes. -#include "../Indicator/tests/classes/IndicatorTfDummy.h" -#include "../Indicators/Oscillator/Indi_RSI.h" -#include "../Indicators/Tick/Indi_TickMt.h" -#include "../Platform/Chart/ChartMt.h" -#include "../Strategy.mqh" -#include "../Test.mqh" +#include "../../Indicator/tests/classes/IndicatorTfDummy.h" +#include "../../Indicators/Oscillator/Indi_RSI.h" +#include "../../Indicators/Tick/Indi_TickMt.h" +#include "../../Platform/Chart/ChartMt.h" +#include "../Strategy.h" +#include "../../Test.mqh" // Define strategy classes. class Stg_RSI : public Strategy { @@ -70,8 +70,8 @@ class Stg_RSI : public Strategy { IndiRSIParams _iparams = _indi.GetParams(); double _trail = _level * Market().GetPipSize(); int _direction = Order::OrderDirection(_cmd, _mode); - return _direction > 0 ? (float)_indi.GetPrice(PRICE_HIGH, _indi.GetHighest(_iparams.GetPeriod() * 2)) - : (float)_indi.GetPrice(PRICE_LOW, _indi.GetLowest(_iparams.GetPeriod() * 2)); + return _direction > 0 ? (float)_indi.GetPrice(PRICE_HIGH, _indi.GetHighest(_iparams.GetPeriod() * 2)) + : (float)_indi.GetPrice(PRICE_LOW, _indi.GetLowest(_iparams.GetPeriod() * 2)); } virtual void OnPeriod(unsigned int _periods = DATETIME_NONE) { diff --git a/tests/Strategy.test.cpp b/Strategy/tests/Strategy.test.cpp similarity index 94% rename from tests/Strategy.test.cpp rename to Strategy/tests/Strategy.test.cpp index 30f554008..a3af9807d 100644 --- a/tests/Strategy.test.cpp +++ b/Strategy/tests/Strategy.test.cpp @@ -25,8 +25,8 @@ */ // Includes. -#include "../Strategy.mqh" -#include "../Platform/Platform.h" +#include "../Strategy.h" +#include "../../Platform/Platform.h" int main(int argc, char **argv) { // @todo diff --git a/tests/StrategyTest.mq4 b/Strategy/tests/Strategy.test.mq4 similarity index 97% rename from tests/StrategyTest.mq4 rename to Strategy/tests/Strategy.test.mq4 index 981f90c9e..6fd28390f 100644 --- a/tests/StrategyTest.mq4 +++ b/Strategy/tests/Strategy.test.mq4 @@ -25,4 +25,4 @@ */ // Includes. -#include "StrategyTest.mq5" +#include "Strategy.test.mq5" diff --git a/tests/StrategyTest.mq5 b/Strategy/tests/Strategy.test.mq5 similarity index 98% rename from tests/StrategyTest.mq5 rename to Strategy/tests/Strategy.test.mq5 index 6ebf91b9e..468f7963e 100644 --- a/tests/StrategyTest.mq5 +++ b/Strategy/tests/Strategy.test.mq5 @@ -28,9 +28,9 @@ struct DataParamEntry; // Includes. -#include "../Indicators/Indi_Demo.mqh" -#include "../Strategy.mqh" -#include "../Test.mqh" +#include "../../Indicators/Indi_Demo.mqh" +#include "../Strategy.h" +#include "../../Test.mqh" // Define strategy classes. class Stg1 : public Strategy { diff --git a/Task/Task.h b/Task/Task.h index 548df0483..7f21b9665 100644 --- a/Task/Task.h +++ b/Task/Task.h @@ -320,11 +320,10 @@ class Task : public Taskable { #include EMSCRIPTEN_BINDINGS(Task) { - emscripten::class_("Task").smart_ptr>("Ref").constructor(emscripten::optional_override([]() { - return Ref(new Task()); - })) - //.function("Add", optional_override([](Task &self, Ref task) { self.Add(task.Ptr()); })) - ; + emscripten::class_("Task") + .smart_ptr>("Ref") + .constructor(emscripten::optional_override([]() { return Ref(new Task()); })) + .function("Add", emscripten::optional_override([](Task &self, TaskEntry taskEntry) { self.Add(taskEntry); })); } #endif diff --git a/Task/TaskAction.struct.h b/Task/TaskAction.struct.h index 367967349..a40115cde 100644 --- a/Task/TaskAction.struct.h +++ b/Task/TaskAction.struct.h @@ -30,10 +30,10 @@ #endif // Includes. -#include "../Storage/Data.struct.h" +#include "../Platform/Terminal.define.h" #include "../Serializer/Serializer.define.h" #include "../Std.h" -#include "../Platform/Terminal.define.h" +#include "../Storage/Data.struct.h" #include "Task.enum.h" // Forward declarations. @@ -99,6 +99,7 @@ struct TaskActionEntry { } void SetFlags(unsigned char _flags) { flags = _flags; } // State methods. + bool HasArgs() const { return ::ArraySize(args) > 0; } bool HasTriesLeft() const { return tries > 0 || tries == -1; } bool IsActive() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_ACTIVE)); } bool IsDone() const { return HasFlag(STRUCT_ENUM(TaskActionEntry, TASK_ACTION_ENTRY_FLAG_IS_DONE)); } @@ -126,7 +127,13 @@ struct TaskActionEntry { SetUserError(ERR_INVALID_PARAMETER); return InvalidEnumValue::value(); } - DataParamEntry GetArg(int _index) const { return args[_index]; } + DataParamEntry GetArg(int _index) const { + if (_index < 0 || _index >= ArraySize(args)) { + Alert(string("Error at ") + __FUNCSIG__ + ": index " + IntegerToString(_index) + " is out of bounds. There are " + + IntegerToString(ArraySize(args)) + " arguments in the task action."); + } + return args[_index]; + } int GetId() const { return id; } // Setters. void TriesDec() { diff --git a/Task/tests/Makefile b/Task/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Task/tests/Makefile +++ b/Task/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Tick/tests/Makefile b/Tick/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Tick/tests/Makefile +++ b/Tick/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/Trade.enum.h b/Trade.enum.h index 560e4831c..89190879e 100644 --- a/Trade.enum.h +++ b/Trade.enum.h @@ -74,7 +74,7 @@ enum ENUM_TRADE_CONDITION { TRADE_COND_ORDERS_PROFIT_LT_ARG, // Equity >= (arg) TRADE_COND_ORDERS_PROFIT_GT_RISK_MARGIN, // Equity >= Risk Margin TRADE_COND_ORDERS_PROFIT_LT_RISK_MARGIN, // Equity <= Risk Margin - FINAL_ENUM_TRADE_CONDITION_ENTRY = 4 + FINAL_ENUM_TRADE_CONDITION_ENTRY }; // Defines enumeration for trade parameters. diff --git a/Trade.mqh b/Trade.mqh index 4ada25cb4..cc38d285f 100644 --- a/Trade.mqh +++ b/Trade.mqh @@ -36,6 +36,7 @@ class Trade; #include "Math/Math.h" #include "Platform/Order.h" #include "Platform/OrderQuery.h" +#include "Serializer/Serializer.ref.h" #include "Storage/Dict/DictStruct.h" #include "Storage/Object.h" #include "Task/TaskManager.h" @@ -914,7 +915,7 @@ HistorySelect(0, TimeCurrent()); // Select history for access. */ int OrdersCloseViaCmd(ENUM_ORDER_TYPE _cmd, ENUM_ORDER_REASON_CLOSE _reason = ORDER_REASON_CLOSED_UNKNOWN, string _comment = "") { - int _oid = 0, _closed = 0; + int _closed = 0; Ref _order; _comment = _comment != "" ? _comment : "TOCVC:"; for (DictStructIterator> iter = orders_active.Begin(); iter.IsValid(); ++iter) { diff --git a/Trade.struct.h b/Trade.struct.h index fa3fad96e..f1dff61a9 100644 --- a/Trade.struct.h +++ b/Trade.struct.h @@ -97,7 +97,8 @@ struct TradeStats { for (int t = 0; t < FINAL_ENUM_TRADE_STAT_TYPE; t++) { order_stats[t][(int)_period] = 0; #ifdef __debug_verbose__ - Print("Resetting trade counter for type ", EnumToString(t), " and period ", EnumToString(_period)); + Print("Resetting trade counter for type ", EnumToString((ENUM_TRADE_STAT_PERIOD)t), " and period ", + EnumToString(_period)); #endif dt[t][(int)_period].GetStartedPeriods(true, true); } @@ -140,23 +141,23 @@ struct TradeParams { ENUM_LOG_LEVEL log_level; // Log verbosity level. // Constructors. TradeParams(float _lot_size = 0, float _risk_margin = 1.0f, unsigned int _slippage = 0, ENUM_LOG_LEVEL _ll = V_INFO) - : bars_min(100), + : lot_size(_lot_size), + risk_margin(_risk_margin), order_comment(""), - log_level(_ll), - lot_size(_lot_size), + slippage(_slippage), magic_no(0), - risk_margin(_risk_margin), - slippage(_slippage) { + bars_min(100), + log_level(_ll) { SetLimits(0); } TradeParams(uint64 _magic_no, ENUM_LOG_LEVEL _ll = V_INFO) - : bars_min(100), - lot_size(0), + : lot_size(0), + risk_margin(1.0f), order_comment(""), - log_level(_ll), + slippage(0), magic_no(_magic_no), - risk_margin(1.0f), - slippage(0) {} + bars_min(100), + log_level(_ll) {} TradeParams(const TradeParams &_tparams) { THIS_REF = _tparams; } // Deconstructor. ~TradeParams() {} diff --git a/Trade/tests/Makefile b/Trade/tests/Makefile index e792364f0..ba14b9322 100644 --- a/Trade/tests/Makefile +++ b/Trade/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O) diff --git a/tests/CompileTest.mq5 b/tests/CompileTest.mq5 index 6cc33363b..bc7f1602a 100644 --- a/tests/CompileTest.mq5 +++ b/tests/CompileTest.mq5 @@ -57,6 +57,7 @@ struct IndicatorParams; #include "../Storage/Dict/DictObject.h" #include "../Storage/Dict/DictSlot.h" #include "../Storage/Dict/DictStruct.h" +#include "../Storage/Instances.h" #include "../Platform/Plot.h" #include "../Indicators/DrawIndicator.mqh" #include "../EA.mqh" @@ -73,7 +74,7 @@ struct IndicatorParams; #include "../Storage/Object.h" #include "../Platform/Order.h" #include "../Platform/Orders.h" -#include "../Pattern.mqh" +#include "../Platform/Chart/Pattern.h" // #include "../Profiler.mqh" #include "../Storage/Redis.h" #include "../Refs.mqh" @@ -84,7 +85,7 @@ struct IndicatorParams; #include "../Socket.mqh" #include "../Std.h" #include "../Storage/Singleton.h" -#include "../Strategy.mqh" +#include "../Strategy/Strategy.h" #include "../Storage/String.h" #include "../SummaryReport.mqh" #include "../Exchange/SymbolInfo/SymbolInfo.h" diff --git a/tests/EA.test.cpp b/tests/EA.test.cpp index 5a93ec93c..da21c1384 100644 --- a/tests/EA.test.cpp +++ b/tests/EA.test.cpp @@ -26,10 +26,10 @@ // Includes. #include "../EA.mqh" + #include "../Platform/Platform.h" int main(int argc, char **argv) { // @todo - return 0; } diff --git a/tests/EATest.mq5 b/tests/EATest.mq5 index 23b0b731f..810e909e5 100644 --- a/tests/EATest.mq5 +++ b/tests/EATest.mq5 @@ -32,6 +32,8 @@ struct DataParamEntry; #include "../Exchange/Account/Account.struct.h" #include "../Test.mqh" +DictStruct> _trades_test; + // Defines EA classes. class EA1 : public EA { public: @@ -57,6 +59,9 @@ EA3 *ea3; * Implements OnInit(). */ int OnInit() { + Platform::Init(); + Platform::SetSymbolTfForTesting("EURUSD", PERIOD_M1); + // Task to export to all possible formats once per hour. TaskEntry _task_export_per_hour(EA_ACTION_EXPORT_DATA, EA_COND_ON_NEW_HOUR); @@ -104,6 +109,12 @@ void OnTick() { * Implements OnDeinit(). */ void OnDeinit(const int reason) { + // Run data export via task. + TaskActionEntry _task_run_export(EA_ACTION_EXPORT_DATA); + ea1.Run(_task_run_export); + ea2.Run(_task_run_export); + ea3.Run(_task_run_export); + // Clean up. delete ea1; delete ea2; delete ea3; diff --git a/tests/Makefile b/tests/Makefile index e792364f0..ba14b9322 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,12 +1,40 @@ CC := g++ # C++ compiler -CFLAGS := -Wall -Wextra -std=c++17 -w # Compiler flags -SRCS := $(wildcard *.cpp) # Get all .cpp files in the current directory -OBJS := $(SRCS:.cpp=.o) # Object files corresponding to the source files +MTE4 := metaeditor.exe +MTE5 := metaeditor64.exe +CFLAGS := -Wall -Wextra -std=c++17 -w +SRCS_CPP := $(wildcard *.cpp) +SRCS_MQ4 := $(wildcard *.mq4) +SRCS_MQ5 := $(wildcard *.mq5) +OBJS_EX4 := $(SRCS_MQ4:.mq4=.ex4) +OBJS_EX5 := $(SRCS_MQ5:.mq5=.ex5) +OBJS_O := $(SRCS_CPP:.cpp=.o) -all: $(OBJS) +# Check if the system is Linux +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Linux) + WINE := wine + # Set WINEPATH to include MetaTrader directory. + export WINEPATH := $(WINEPATH);"C:\Program Files\MetaTrader 4;C:\Program Files\MetaTrader 5" +else + WINE := +endif + +.PHONY: all cpp mql mql4 mql5 + +all: $(OBJS_O) +cpp: $(OBJS_O) +mql4: $(OBJS_EX4) +mql5: $(OBJS_EX5) +mql: mql4 mql5 + +%.ex4: %.mq4 + $(WINE) $(MTE4) /compile:$< /log:CON + +%.ex5: %.mq5 + $(WINE) $(MTE5) /compile:$< /log:CON %.o: %.cpp $(CC) $(CFLAGS) -c $< -o $@ clean: - rm -v $(OBJS) + rm -v $(OBJS_EX4) $(OBJS_EX5) $(OBJS_O)