From d50eef35bc3ab62db77a67ca6c7daf17e348593b Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Thu, 13 Aug 2026 00:36:57 +0330 Subject: [PATCH] add and Test Context Generator ... --- ContextGenerator.js | 557 + .../xDashboard-20260813_013548.txt | 77693 ++++++++++++++++ 2 files changed, 78250 insertions(+) create mode 100644 ContextGenerator.js create mode 100644 Documents/GeneratedContext/xDashboard-20260813_013548.txt diff --git a/ContextGenerator.js b/ContextGenerator.js new file mode 100644 index 00000000..7b38bc2b --- /dev/null +++ b/ContextGenerator.js @@ -0,0 +1,557 @@ +#!/usr/bin/env node + +/** + * Context Generator Module ... + * a module for Generating Context ... + * + * Maintainer + * + * Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +*/ + +// +//#region Imports ... +const fs = require("fs"); +const path = require("path"); +//#endregion + +// +//#region Constants ... +const outputFilePrefix = "xDashboard"; +const allowedPatterns = [ + // { + // kind: "file", + // mode: "allow", + // match: "name", + // pattern: /^*.mq5$/i + // }, + // { + // kind: "directory", + // mode: "deny", + // match: "name", + // pattern: /^node_modules$/i + // }, + // { + // kind: "file", + // mode: "allow", + // match: "path", + // pattern: /^x-saherelm.*.mq5$/i + // }, + + // + // Base Pilot Files ... + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.base.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.session-detector.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-account.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-alert.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-app-dialog.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-backtester.expert.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-bar.analyser.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-chart.helper.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-cobject.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-data.collector.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-expert.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-guard.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-helper.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-http.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-market.pattern.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-md5.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-poi.drawer.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-position.drawer.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-restrictions.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-rm.panel.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-signaller.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-target.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-trade-manager.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-trade.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-volume.class.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.backtester.ea.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-expert.ea.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x121.xcc.helper.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x121.xct.helper.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x121.xcc.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x121.xct.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.common.extensions.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.common.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.common.models.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.draw.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-enums.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-guard.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-ohcl.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-pivot.analysis.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-poi.extensions.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-poi.lib.mq5$/i + }, + { + kind: "file", + mode: "allow", + match: "name", + pattern: /^x-saherelm.x-trade.lib.mq5$/i + }, +] +//#endregion + +// +// Reading Required Info +const inputPath = process.argv[2]; +const searchPath = path.resolve(inputPath || process.cwd()); + +// Check Given Path is Valid or not ... +if (!fs.existsSync(searchPath)) { + console.error(`Error: path not found: ${searchPath}`); + process.exit(1); +} + +// +// Retrieve Stats of Given Path ... +const stat = fs.statSync(searchPath); +if (!stat.isDirectory()) { + console.error(`Error: path is not a directory: ${searchPath}`); + process.exit(1); +} + +// +// Generate Required Data ... +const timestamp = getTimestamp(new Date()); +const folderName = path.basename(searchPath) || "root"; +const safeFolderName = sanitizeFileName(folderName); + +// Generate Output file Name ... +const outputFileName = inputPath + ? `${outputFilePrefix}-${safeFolderName}-${timestamp}.txt` + : `${outputFilePrefix}-${timestamp}.txt`; + +// +const outputPath = path.join( + process.cwd(), + "Documents", + "GeneratedContext", + outputFileName +); + +// Create Output File ... +fs.writeFileSync(outputPath, "", "utf8"); + +// Navigate to Context Generation ... +walk(searchPath); + +// +console.log(`Context generated: ${outputPath}`); + +// +//#region Required Tools ... +/** + * Validate Timestamp ... + * + * @param {*} value + * @returns + */ +function pad(value) { + return String(value).padStart(2, "0"); +} + +/** + * Retrieve Validate ... + * + * @param {*} date + * @returns + */ +function getTimestamp(date) { + // + const year = date.getFullYear(); + const month = pad(date.getMonth() + 1); + const day = pad(date.getDate()); + const hours = pad(date.getHours()); + const minutes = pad(date.getMinutes()); + const seconds = pad(date.getSeconds()); + + // + return `${year}${month}${day}_${hours}${minutes}${seconds}`; +} + +/** + * Retrieve Leaf Folder ... + * + * @param {*} value + * @returns + */ +function sanitizeFileName(value) { + return value.replace(/[\\/:*?"<>|]/g, "_"); +} + +/** + * Match Value ... + * + * @param {*} rule + * @param {*} targetPath + * @returns + */ +function getMatchValue(rule, targetPath) { + // + const normalizedPath = targetPath.replace(/\\/g, "/"); + if (rule.match === "path") { + return normalizedPath; + } + + // + return path.basename(targetPath); +} + +/** + * Match Patterns ... + * + * @param {*} targetPath + * @param {*} rules + * @returns + */ +function matchesPatterns(targetPath, rules) { + // + return rules.some(rule => { + const value = getMatchValue(rule, targetPath); + return rule.pattern.test(value); + }); +} + +/** + * Check a Directory Path is Valid for Parsing or not ... + * + * @param {*} fileName + * @returns + */ +function isAllowedFile(filePath) { + // + // Extract Deny Rules ... + const denyRules = allowedPatterns.filter( + p => p.kind === "file" && p.mode === "deny" + ); + + // + // Extract Allowed Rules ... + const allowRules = allowedPatterns.filter( + p => p.kind === "file" && p.mode === "allow" + ); + + // Check Deny Rules First ... + if (matchesPatterns(filePath, denyRules)) { + return false; + } + + // Check Allowed Rules ... + return matchesPatterns(filePath, allowRules); +} + +/** + * Check a Directory Path is Valid for Parsing or not ... + * + * @param {*} directoryPath + * @returns + */ +function isAllowedDirectory(directoryPath) { + // + // Extract Deny Rules ... + const denyRules = allowedPatterns.filter( + p => p.kind === "directory" && p.mode === "deny" + ); + + // + // Extract Allowed Rules ... + const allowRules = allowedPatterns.filter( + p => p.kind === "directory" && p.mode === "allow" + ); + + // + // Check Deny Patterns as First ... + if (matchesPatterns(directoryPath, denyRules)) { + return false; + } + + // + // Check Allow Patterns Exists ... + if (allowRules.length === 0) { + return true; + } + + // + // Chck Allowed Patterns Matched ... + return matchesPatterns(directoryPath, allowRules); +} + +/** + * Loop through a Directory and Navigate files for including in Context ... + * + * @param {*} dir + * @returns + */ +function walk(dir) { + // + // Reading Directory Content ... + let entries; + try { + entries = fs.readdirSync(dir, { withFileTypes: true }); + } catch (error) { + fs.appendFileSync( + outputPath, + `\n### ERROR reading directory: ${dir}\n${error.message}\n`, + "utf8" + ); + return; + } + + // + // Loop through Entries ... + for (const entry of entries) { + // + const fullPath = path.join(dir, entry.name); + + // + // Ignore if Symlink ... + if (entry.isSymbolicLink()) { + continue; + } + + // + // Handle if requested Path is Directory ... + if (entry.isDirectory()) { + // + // Allowed Folders ... + if (!isAllowedDirectory(fullPath)) { + continue; + } + + // + walk(fullPath); + } + else + // + // Handle if requested Path is File ... + if (entry.isFile()) { + // + // Allowed File ... + if (!isAllowedFile(fullPath)) { + continue; + } + + // + // Holds File Content ... + let content; + try { + content = fs.readFileSync(fullPath, "utf8"); + } catch (error) { + content = `// Error reading file: ${error.message}`; + } + + // + // Append File Content for Context ... + fs.appendFileSync( + outputPath, + `\n### FILE: ${fullPath}\n\n${content}\n`, + "utf8" + ); + } + } +} +//#endregion diff --git a/Documents/GeneratedContext/xDashboard-20260813_013548.txt b/Documents/GeneratedContext/xDashboard-20260813_013548.txt new file mode 100644 index 00000000..353dac32 --- /dev/null +++ b/Documents/GeneratedContext/xDashboard-20260813_013548.txt @@ -0,0 +1,77693 @@ + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.base.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XBaseClass +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// XBase Class ... +class XCBase +{ + // + // Public ... + public: + // + // Protected ... + + // + // Represent Basic Unique Tag ... + virtual string GetTag() { + return NULL; + } + + // + // Retrieve Class Token ... + virtual string GetToken() { + return NULL; + } + + // + // Protected + protected: + // + // Private ... + private: +}; + +// +template +string GenerateSpecifiedCommonSummary( + T &mItem, + string separator = "\n", + bool includeScores = true, + bool setLabel = false // +) +{ + // + string result = NULL; + + // + double bullishScore = 0; + double bearishScore = 0; + mItem.GenerateScore( + bullishScore, + bearishScore // + ); + + // + result = + // + (!setLabel + ? "" + : "Commons:" + separator) + + "---------------" + separator + + "Symbol: " + mItem.symbol + separator + + "Period: " + ToXString(mItem.period) + separator + + "Time: " + ToXString(mItem.time) + separator + + (includeScores + ? "---------------" + separator + + "Scores:" + separator + + "---------------" + separator + + "Bullish: " + ToXString(bullishScore) + separator + + "Bearish: " + ToXString(bearishScore) + separator + + "---------------" + separator + : "") + + "" + // + ; + + // + return result; +} + +// + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.session-detector.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCSessionDetector +// Description: Forex Session Detector with Event System +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// + +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm Forex Session Detector Class" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Libraries/x-saherelm.common.extensions.lib.mq5" +#include "../Libraries/x-saherelm.x-enums.lib.mq5" + +// +// Definitions ... + +// #region Session Types ... +// +// Forex Session Types ... +enum ENUM_X_SESSION_TYPE +{ + X_SESSION_NONE = 0, // None + X_SESSION_SYDNEY = 1, // Sydney Session + X_SESSION_TOKYO = 2, // Tokyo Session + X_SESSION_LONDON = 3, // London Session + X_SESSION_NEWYORK = 4, // New York Session + X_SESSION_FRANKFURT = 5, // Frankfurt Session + X_SESSION_SINGAPORE = 6, // Singapore Session + X_SESSION_HONGKONG = 7, // Hong Kong Session +}; + +/** + * Validate ... + * + * @param value: ENUM_X_SESSION_TYPE member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_SESSION_TYPE value) +{ + // + bool result = false; + + // + result = + value != NULL && + value != X_SESSION_NONE; + + // + return result; +} +bool IsXValid(ENUM_X_SESSION_TYPE value) +{ + return IsValid(value); +} + +/** + * Cpnverts to String ... + * + * @param value: ENUM_X_SESSION_TYPE ... + * + * @return ( string ) + */ +string ToXString(ENUM_X_SESSION_TYPE value) +{ + // + string result = NULL; + + // + if (value == NULL) + { + return result; + } + + // + switch (value) + { + // + case X_SESSION_NONE: + result = "NONE"; + break; + + // + case X_SESSION_SYDNEY: + result = "SYDNEY"; + break; + + // + case X_SESSION_TOKYO: + result = "TOKYO"; + break; + + // + case X_SESSION_LONDON: + result = "LONDON"; + break; + + // + case X_SESSION_NEWYORK: + result = "NEWYORK"; + break; + + // + case X_SESSION_FRANKFURT: + result = "FRANKFURT"; + break; + + // + case X_SESSION_SINGAPORE: + result = "SINGAPORE"; + break; + + // + case X_SESSION_HONGKONG: + result = "HONGKONG"; + break; + } + + // + return result; +} + +/** + * Parse From String ... + * + * @param value: string ... + * + * @return ( ENUM_X_SESSION_TYPE ) + */ +ENUM_X_SESSION_TYPE FromXString(string value) +{ + // + ENUM_X_SESSION_TYPE result = X_SESSION_NONE; + + // + // Validate ... + if (!IsXValid(value)) + { + return result; + } + + // + if (value == ToXString(X_SESSION_NONE)) + { + result = X_SESSION_NONE; + } + else if (value == ToXString(X_SESSION_SYDNEY)) + { + result = X_SESSION_SYDNEY; + } + else if (value == ToXString(X_SESSION_TOKYO)) + { + result = X_SESSION_TOKYO; + } + else if (value == ToXString(X_SESSION_LONDON)) + { + result = X_SESSION_LONDON; + } + else if (value == ToXString(X_SESSION_NEWYORK)) + { + result = X_SESSION_NEWYORK; + } + else if (value == ToXString(X_SESSION_FRANKFURT)) + { + result = X_SESSION_FRANKFURT; + } + else if (value == ToXString(X_SESSION_SINGAPORE)) + { + result = X_SESSION_SINGAPORE; + } + else if (value == ToXString(X_SESSION_HONGKONG)) + { + result = X_SESSION_HONGKONG; + } + + // + return result; +} +// #endregion + +// #region Session Overlap Types ... +// +// Session Overlap Types ... +enum ENUM_X_SESSION_OVERLAP_TYPE +{ + X_OVERLAP_NONE = 0, // None + X_OVERLAP_SYDNEY_TOKYO = 1, // Sydney-Tokyo Overlap + X_OVERLAP_TOKYO_LONDON = 2, // Tokyo-London Overlap + X_OVERLAP_LONDON_NEWYORK = 3, // London-New York Overlap (Most Liquid) + X_OVERLAP_LONDON_FRANKFURT = 4, // London-Frankfurt Overlap + X_OVERLAP_NEWYORK_SYDNEY = 5, // New York-Sydney Overlap + X_OVERLAP_TOKYO_SINGAPORE = 6, // Tokyo-Singapore Overlap + X_OVERLAP_HONGKONG_TOKYO = 7, // Hong Kong-Tokyo Overlap +}; + +/** + * Validate ... + * + * @param value: ENUM_X_SESSION_OVERLAP_TYPE member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_SESSION_OVERLAP_TYPE value) +{ + // + bool result = false; + + // + result = + value != NULL && + value != X_OVERLAP_NONE; + + // + return result; +} +bool IsXValid(ENUM_X_SESSION_OVERLAP_TYPE value) +{ + return IsValid(value); +} + +/** + * Cpnverts to String ... + * + * @param value: ENUM_X_SESSION_OVERLAP_TYPE ... + * + * @return ( string ) + */ +string ToXString(ENUM_X_SESSION_OVERLAP_TYPE value) +{ + // + string result = NULL; + + // + // Validate ... + if (value == NULL) + { + return result; + } + + // + switch (value) + { + // + case X_OVERLAP_NONE: + result = "NONE"; + break; + + // + case X_OVERLAP_SYDNEY_TOKYO: + result = "SYDNEY_TOKYO"; + break; + + // + case X_OVERLAP_TOKYO_LONDON: + result = "TOKYO_LONDON"; + break; + + // + case X_OVERLAP_LONDON_NEWYORK: + result = "LONDON_NEWYORK"; + break; + + // + case X_OVERLAP_LONDON_FRANKFURT: + result = "LONDON_FRANKFURT"; + break; + + // + case X_OVERLAP_NEWYORK_SYDNEY: + result = "NEWYORK_SYDNEY"; + break; + + // + case X_OVERLAP_TOKYO_SINGAPORE: + result = "TOKYO_SINGAPORE"; + break; + + // + case X_OVERLAP_HONGKONG_TOKYO: + result = "HONGKONG_TOKYO"; + break; + } + + // + return result; +} +// #endregion + +// #region Session State ... +// +// Session State ... +enum ENUM_X_SESSION_STATE +{ + X_SESSION_STATE_INACTIVE = 0, // Session Not Active + X_SESSION_STATE_ACTIVE = 1, // Session Active + X_SESSION_STATE_STARTING = 2, // Session Starting (First Bar) + X_SESSION_STATE_ENDING = 3, // Session Ending (Last Bar) +}; + +/** + * Check a Session State is Active or not ... + * + * @param value: ENUM_X_SESSION_STATE + * + * @return ( bool ) + */ +bool IsXActive(ENUM_X_SESSION_STATE value) +{ + // + bool result = false; + + // + result = + value == X_SESSION_STATE_ACTIVE; + + // + return result; +} +// #endregion + +// #region Event Handler Types ... +typedef void (*TOnSessionStart)(ENUM_X_SESSION_TYPE session, datetime startTime); +typedef void (*TOnSessionEnd)(ENUM_X_SESSION_TYPE session, datetime endTime); +typedef void (*TOnOverlapStart)(ENUM_X_SESSION_OVERLAP_TYPE overlap, datetime startTime); +typedef void (*TOnOverlapEnd)(ENUM_X_SESSION_OVERLAP_TYPE overlap, datetime endTime); +typedef void (*TOnSessionStateChange)(ENUM_X_SESSION_TYPE session, ENUM_X_SESSION_STATE state); +// #endregion + +// #region Session Configuration ... +struct XSessionConfig +{ + // + string name; // Session Name + ENUM_X_SESSION_TYPE type; // Session Type + string startTime; // Start Time (HH:MM) + string endTime; // End Time (HH:MM) + color sessionColor; // Session Color for Visualization + bool isActive; // Is Session Active + datetime lastStartTime; // Last Start Time + datetime lastEndTime; // Last End Time + ENUM_X_SESSION_STATE state; // Current State + + // + // Constructor ... + XSessionConfig() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + name = NULL; + type = X_SESSION_NONE; + startTime = NULL; + endTime = NULL; + sessionColor = CLR_NONE; + isActive = false; + lastStartTime = NULL; + lastEndTime = NULL; + state = X_SESSION_STATE_INACTIVE; + + // + ZeroMemory(this); + } + + // + void Default(ENUM_X_SESSION_TYPE _type) + { + // + Clean(); + + // + // Validate ... + if (!IsXValid(_type)) + { + return; + } + + // + type = _type; + name = ToXString(_type); + + // + switch (_type) + { + // + case X_SESSION_SYDNEY: + startTime = "22:00"; + endTime = "07:00"; + sessionColor = clrAqua; + break; + + // + case X_SESSION_TOKYO: + startTime = "00:00"; + endTime = "09:00"; + sessionColor = clrYellow; + break; + + // + case X_SESSION_SINGAPORE: + startTime = "01:00"; + endTime = "09:00"; + sessionColor = clrOrange; + break; + + // + case X_SESSION_HONGKONG: + startTime = "01:00"; + endTime = "09:00"; + sessionColor = clrGold; + break; + + // + case X_SESSION_FRANKFURT: + startTime = "07:00"; + endTime = "16:00"; + sessionColor = clrLime; + break; + + // + case X_SESSION_LONDON: + startTime = "08:00"; + endTime = "17:00"; + sessionColor = clrGreen; + break; + + // + case X_SESSION_NEWYORK: + startTime = "13:00"; + endTime = "22:00"; + sessionColor = clrRed; + break; + + // + default: + name = "Unknown"; + startTime = "00:00"; + endTime = "00:00"; + sessionColor = clrGray; + break; + } + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + IsXValid(type) && + IsXValid(name) && + IsXValid(startTime) && + IsXValid(endTime); + + // + return result; + } +}; +// #endregion + +// #region Overlap Configuration ... +struct XOverlapConfig +{ + // + string name; // Overlap Name + ENUM_X_SESSION_OVERLAP_TYPE type; // Overlap Type + ENUM_X_SESSION_TYPE session1; // First Session + ENUM_X_SESSION_TYPE session2; // Second Session + string overlapStartTime; // Overlap Start Time + string overlapEndTime; // Overlap End Time + color overlapColor; // Overlap Color + bool isActive; // Is Overlap Active + datetime lastStartTime; // Last Start Time + datetime lastEndTime; // Last End Time + + // + // Constructor ... + XOverlapConfig() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + name = NULL; + type = X_OVERLAP_NONE; + session1 = X_SESSION_NONE; + session2 = X_SESSION_NONE; + overlapStartTime = NULL; + overlapEndTime = NULL; + overlapColor = CLR_NONE; + isActive = false; + lastStartTime = NULL; + lastEndTime = NULL; + + // + ZeroMemory(this); + } + + // + void Default(ENUM_X_SESSION_OVERLAP_TYPE _type) + { + // + Clean(); + + // + if (!IsXValid(_type)) + { + return; + } + + // + type = _type; + name = ToXString(_type); + + // + switch (_type) + { + // + case X_OVERLAP_SYDNEY_TOKYO: + session1 = X_SESSION_SYDNEY; + session2 = X_SESSION_TOKYO; + overlapStartTime = "00:00"; + overlapEndTime = "07:00"; + overlapColor = clrYellow; + break; + + // + case X_OVERLAP_TOKYO_LONDON: + session1 = X_SESSION_TOKYO; + session2 = X_SESSION_LONDON; + overlapStartTime = "08:00"; + overlapEndTime = "09:00"; + overlapColor = clrLime; + break; + + // + case X_OVERLAP_LONDON_NEWYORK: + session1 = X_SESSION_LONDON; + session2 = X_SESSION_NEWYORK; + overlapStartTime = "13:00"; + overlapEndTime = "17:00"; + overlapColor = clrOrange; + break; + + // + case X_OVERLAP_LONDON_FRANKFURT: + session1 = X_SESSION_LONDON; + session2 = X_SESSION_FRANKFURT; + overlapStartTime = "08:00"; + overlapEndTime = "16:00"; + overlapColor = clrGreen; + break; + + // + case X_OVERLAP_NEWYORK_SYDNEY: + session1 = X_SESSION_NEWYORK; + session2 = X_SESSION_SYDNEY; + overlapStartTime = "22:00"; + overlapEndTime = "22:00"; + overlapColor = clrPurple; + break; + + // + case X_OVERLAP_TOKYO_SINGAPORE: + session1 = X_SESSION_TOKYO; + session2 = X_SESSION_SINGAPORE; + overlapStartTime = "01:00"; + overlapEndTime = "09:00"; + overlapColor = clrGold; + break; + + // + case X_OVERLAP_HONGKONG_TOKYO: + session1 = X_SESSION_HONGKONG; + session2 = X_SESSION_TOKYO; + overlapStartTime = "01:00"; + overlapEndTime = "09:00"; + overlapColor = clrPink; + break; + + // + default: + name = "Unknown"; + session1 = X_SESSION_NONE; + session2 = X_SESSION_NONE; + overlapStartTime = "00:00"; + overlapEndTime = "00:00"; + overlapColor = clrGray; + break; + } + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + IsXValid(type) && + IsXValid(name) && + IsXValid(session1) && + IsXValid(session2); + + // + return result; + } +}; +// #endregion + +// +// Implementation ... +class XCSessionDetector : public XCBase +{ + // + public: + // + // Props ... + // + XCAlert *alert; // Alert Handler + XSessionConfig sessions[]; // All Sessions + XOverlapConfig overlaps[]; // All Overlaps + + // + // Event Handlers ... + TOnSessionEnd mOnSessionEndHandlers[]; + TOnOverlapEnd mOnOverlapEndHandlers[]; + TOnSessionStart mOnSessionStartHandlers[]; + TOnOverlapStart mOnOverlapStartHandlers[]; + TOnSessionStateChange mOnSessionStateChangeHandlers[]; + + // + // Time Tracking ... + datetime lastCheckTime; // Last Check Time + int timezoneOffset; // Timezone Offset (in Hours) + bool useServerTime; // Use Server Time or UTC + + // + // Constructor ... + XCSessionDetector( + XCAlert *_alert = NULL, + bool _useServerTime = true, + int _timezoneOffset = 0 // + ) + { + alert = _alert; + useServerTime = _useServerTime; + timezoneOffset = _timezoneOffset; + lastCheckTime = NULL; + + // + InitializeSessions(); + InitializeOverlaps(); + } + + // + // Deconstructor ... + ~XCSessionDetector() + { + // + Clean(sessions); + Clean(overlaps); + Clean(mOnSessionEndHandlers); + Clean(mOnOverlapEndHandlers); + Clean(mOnSessionStartHandlers); + Clean(mOnOverlapStartHandlers); + Clean(mOnSessionStateChangeHandlers); + + // + ZeroMemory(alert); + } + + // #region Getters ... + /** + * Get Session Config by Type + * + * @param sessionType: ENUM_X_SESSION_TYPE + * + * @return ( XSessionConfig ) + */ + XSessionConfig GetSessionConfig(ENUM_X_SESSION_TYPE sessionType) + { + // + XSessionConfig result; + result.Clean(); + + // + if (!IsXValid(sessionType)) + { + return result; + } + + // + int sessionsCount = ArraySize(sessions); + for (int i = 0; i < sessionsCount; i++) + { + // + if (sessions[i].type == sessionType) + { + result = sessions[i]; + break; + } + } + + // + return result; + } + + /** + * Get Overlap Config by Type + * + * @param overlapType: ENUM_X_SESSION_OVERLAP_TYPE + * + * @return ( XOverlapConfig ) + */ + XOverlapConfig GetOverlapConfig(ENUM_X_SESSION_OVERLAP_TYPE overlapType) + { + // + XOverlapConfig result; + result.Clean(); + + // + if (!IsXValid(overlapType)) + { + return result; + } + + // + int overlapsCount = ArraySize(overlaps); + for (int i = 0; i < overlapsCount; i++) + { + // + if (overlaps[i].type == overlapType) + { + result = overlaps[i]; + break; + } + } + + // + return result; + } + + /** + * Get Current Active Session + * + * @param currentTime: datetime + * + * @return ( ENUM_X_SESSION_TYPE ) + */ + ENUM_X_SESSION_TYPE GetCurrentSession(datetime currentTime = NULL) + { + // + ENUM_X_SESSION_TYPE result = X_SESSION_NONE; + + // + if (!IsXValid(currentTime)) + { + currentTime = GetCurrentTime(); + } + + // + int sessionsCount = ArraySize(sessions); + for (int i = 0; i < sessionsCount; i++) + { + // + if (IsSessionActive(sessions[i].type, currentTime)) + { + result = sessions[i].type; + break; + } + } + + // + return result; + } + + /** + * Get Current Active Overlap + * + * @param currentTime: datetime + * + * @return ( ENUM_X_SESSION_OVERLAP_TYPE ) + */ + ENUM_X_SESSION_OVERLAP_TYPE GetCurrentOverlap(datetime currentTime = NULL) + { + // + ENUM_X_SESSION_OVERLAP_TYPE result = X_OVERLAP_NONE; + + // + if (!IsXValid(currentTime)) + { + currentTime = GetCurrentTime(); + } + + // + int overlapsCount = ArraySize(overlaps); + for (int i = 0; i < overlapsCount; i++) + { + // + if (IsOverlapActive(overlaps[i], currentTime)) + { + result = overlaps[i].type; + break; + } + } + + // + return result; + } + // #endregion + + // #region Tools & Actions ... + /** + * Initialize All Forex Sessions + */ + void InitializeSessions() + { + // + Clean(sessions); + + // + // Sydney Session + XSessionConfig sydney; + sydney.Default(X_SESSION_SYDNEY); + AddRef(sydney, sessions); + + // + // Tokyo Session + XSessionConfig tokyo; + tokyo.Default(X_SESSION_TOKYO); + AddRef(tokyo, sessions); + + // + // Singapore Session + XSessionConfig singapore; + singapore.Default(X_SESSION_SINGAPORE); + AddRef(singapore, sessions); + + // + // Hong Kong Session + XSessionConfig hongkong; + hongkong.Default(X_SESSION_HONGKONG); + AddRef(hongkong, sessions); + + // + // Frankfurt Session + XSessionConfig frankfurt; + frankfurt.Default(X_SESSION_FRANKFURT); + AddRef(frankfurt, sessions); + + // + // London Session + XSessionConfig london; + london.Default(X_SESSION_LONDON); + AddRef(london, sessions); + + // + // New York Session + XSessionConfig newyork; + newyork.Default(X_SESSION_NEWYORK); + AddRef(newyork, sessions); + } + + /** + * Initialize All Session Overlaps + */ + void InitializeOverlaps() + { + // + Clean(overlaps); + + // + // Sydney-Tokyo Overlap + XOverlapConfig sydneyTokyo; + sydneyTokyo.Default(X_OVERLAP_SYDNEY_TOKYO); + AddRef(sydneyTokyo, overlaps); + + // + // Tokyo-London Overlap + XOverlapConfig tokyoLondon; + tokyoLondon.Default(X_OVERLAP_TOKYO_LONDON); + AddRef(tokyoLondon, overlaps); + + // + // London-New York Overlap (Most Important) + XOverlapConfig londonNewYork; + londonNewYork.Default(X_OVERLAP_LONDON_NEWYORK); + AddRef(londonNewYork, overlaps); + + // + // London-Frankfurt Overlap + XOverlapConfig londonFrankfurt; + londonFrankfurt.Default(X_OVERLAP_LONDON_FRANKFURT); + AddRef(londonFrankfurt, overlaps); + + // + // New York-Sydney Overlap + XOverlapConfig newyorkSydney; + newyorkSydney.Default(X_OVERLAP_NEWYORK_SYDNEY); + AddRef(newyorkSydney, overlaps); + } + + /** + * Get Current Time (Adjusted for Timezone) + * + * @return ( datetime ) + */ + datetime GetCurrentTime() + { + // + datetime currentTime = useServerTime + ? TimeCurrent() + : TimeGMT(); + + // + if (timezoneOffset != 0) + { + currentTime = (datetime)((int)currentTime + (timezoneOffset * 3600)); + } + + // + return currentTime; + } + + /** + * Parse Time String to DateTime (Today's Date + Time) + * + * @param timeString: String (HH:MM format) + * @param baseDate: datetime (Base Date) + * + * @return ( datetime ) + */ + datetime ParseTimeToDateTime( + string timeString, + datetime baseDate // + ) + { + // + datetime result = NULL; + + // + if (!IsXValid(timeString)) + { + return result; + } + + // + MqlDateTime dt; + TimeToStruct(baseDate, dt); + + // + string parts[]; + int partsCount = SplitContent(parts, timeString, ":"); + if (partsCount >= 2) + { + // + dt.hour = (int)parts[0]; + dt.min = (int)parts[1]; + dt.sec = 0; + + // + result = StructToTime(dt); + } + + // + return result; + } + + /** + * Check if Current Time is Within Session Time Range + * + * @param startTime: String (HH:MM) + * @param endTime: String (HH:MM) + * @param currentTime: datetime + * + * @return ( bool ) + */ + bool IsTimeInRange( + string startTime, + string endTime, + datetime currentTime // + ) + { + // + bool result = false; + + // + if (!IsXValid(startTime) || !IsXValid(endTime)) + { + return result; + } + + // + datetime todayStart = ParseTimeToDateTime(startTime, currentTime); + datetime todayEnd = ParseTimeToDateTime(endTime, currentTime); + + // + // Handle Sessions that Cross Midnight + if (todayEnd < todayStart) + { + // + // Session crosses midnight + result = (currentTime >= todayStart || currentTime < todayEnd); + } + else + { + // + // Normal session + result = (currentTime >= todayStart && currentTime < todayEnd); + } + + // + return result; + } + + /** + * Check if Current Time is Within Overlap Time Range + * + * @param overlap: XOverlapConfig reference + * @param currentTime: datetime + * + * @return ( bool ) + */ + bool IsOverlapActive( + XOverlapConfig &overlap, + datetime currentTime // + ) + { + // + bool result = false; + + // + if (!overlap.IsValid()) + { + return result; + } + + // + // Check if Both Sessions are Active + bool session1Active = IsSessionActive(overlap.session1, currentTime); + bool session2Active = IsSessionActive(overlap.session2, currentTime); + + // + result = + session1Active && + session2Active; + + // + return result; + } + + /** + * Check if Specific Session is Active + * + * @param sessionType: ENUM_X_SESSION_TYPE + * @param currentTime: datetime + * + * @return ( bool ) + */ + bool IsSessionActive( + ENUM_X_SESSION_TYPE sessionType, + datetime currentTime // + ) + { + // + bool result = false; + + // + int sessionsCount = ArraySize(sessions); + for (int i = 0; i < sessionsCount; i++) + { + // + if (sessions[i].type == sessionType) + { + // + result = IsTimeInRange( + sessions[i].startTime, + sessions[i].endTime, + currentTime // + ); + + // + break; + } + } + + // + return result; + } + + /** + * Get Active Sessions + * + * @param activeSessions: ENUM_X_SESSION_TYPE collection reference + * @param currentTime: datetime + * + * @return ( int ) + */ + int GetActiveSessions( + ENUM_X_SESSION_TYPE &activeSessions[], + datetime currentTime = NULL // + ) + { + // + int result = 0; + Clean(activeSessions); + + // + if (!IsXValid(currentTime)) + { + currentTime = GetCurrentTime(); + } + + // + int sessionsCount = ArraySize(sessions); + for (int i = 0; i < sessionsCount; i++) + { + // + if (IsSessionActive(sessions[i].type, currentTime)) + { + Add(sessions[i].type, activeSessions); + } + } + + // + result = ArraySize(activeSessions); + + // + return result; + } + + /** + * Get Active Overlaps + * + * @param activeOverlaps: ENUM_X_SESSION_OVERLAP_TYPE collection reference + * @param currentTime: datetime + * + * @return ( int ) + */ + int GetActiveOverlaps( + ENUM_X_SESSION_OVERLAP_TYPE &activeOverlaps[], + datetime currentTime = NULL // + ) + { + // + int result = 0; + Clean(activeOverlaps); + + // + if (!IsXValid(currentTime)) + { + currentTime = GetCurrentTime(); + } + + // + int overlapsCount = ArraySize(overlaps); + for (int i = 0; i < overlapsCount; i++) + { + // + if (IsOverlapActive(overlaps[i], currentTime)) + { + Add(overlaps[i].type, activeOverlaps); + } + } + + // + result = ArraySize(activeOverlaps); + + // + return result; + } + // #endregion + + // #region Processors ... + /** + * Process Session Detection (Call on Every Tick or Bar) + * + * @param currentTime: datetime (Optional, uses current time if NULL) + */ + void Process(datetime currentTime = NULL) + { + // + if (!IsXValid(currentTime)) + { + currentTime = GetCurrentTime(); + } + + // + // Check if Enough Time Passed Since Last Check (Prevent Multiple Fires) + if (IsXValid(lastCheckTime) && + (int)currentTime - (int)lastCheckTime < 60) // Minimum 1 minute between checks + { + return; + } + + // + lastCheckTime = currentTime; + + // + // Process All Sessions + int sessionsCount = ArraySize(sessions); + for (int i = 0; i < sessionsCount; i++) + { + ProcessSession(sessions[i], currentTime); + } + + // + // Process All Overlaps + int overlapsCount = ArraySize(overlaps); + for (int i = 0; i < overlapsCount; i++) + { + ProcessOverlap(overlaps[i], currentTime); + } + } + + /** + * Process Individual Session + * + * @param session: XSessionConfig reference + * @param currentTime: datetime + */ + void ProcessSession( + XSessionConfig &session, + datetime currentTime // + ) + { + // + if (!session.IsValid()) + { + return; + } + + // + bool wasActive = session.isActive; + bool isActive = IsTimeInRange( + session.startTime, + session.endTime, + currentTime // + ); + + // + // Session Started + if (isActive && !wasActive) + { + // + session.isActive = true; + session.lastStartTime = currentTime; + session.state = X_SESSION_STATE_STARTING; + + // + NotifySessionStart(session.type, currentTime); + NotifySessionStateChange(session.type, session.state); + + // + // Log Alert + if (alert != NULL) + { + // + string message = "Session Started: " + session.name + + " at " + TimeToString(currentTime, TIME_DATE | TIME_SECONDS); + + // + alert.SendAlert(message); + } + } + // + // Session Ended + else if (!isActive && wasActive) + { + // + session.isActive = false; + session.lastEndTime = currentTime; + session.state = X_SESSION_STATE_ENDING; + + // + NotifySessionEnd(session.type, currentTime); + NotifySessionStateChange(session.type, session.state); + + // + // Log Alert + if (alert != NULL) + { + // + string message = "Session Ended: " + session.name + + " at " + TimeToString(currentTime, TIME_DATE | TIME_SECONDS); + + // + alert.SendAlert(message); + } + } + // + // Session Active (Ongoing) + else if (isActive && wasActive) + { + session.state = X_SESSION_STATE_ACTIVE; + } + // + // Session Inactive + else + { + session.state = X_SESSION_STATE_INACTIVE; + } + } + + /** + * Process Individual Overlap + * + * @param overlap: XOverlapConfig reference + * @param currentTime: datetime + */ + void ProcessOverlap( + XOverlapConfig &overlap, + datetime currentTime // + ) + { + // + if (!overlap.IsValid()) + { + return; + } + + // + bool wasActive = overlap.isActive; + bool isActive = IsOverlapActive(overlap, currentTime); + + // + // Overlap Started + if (isActive && !wasActive) + { + // + overlap.isActive = true; + overlap.lastStartTime = currentTime; + + // + NotifyOverlapStart(overlap.type, currentTime); + + // + // Log Alert + if (alert != NULL) + { + // + string message = "Overlap Started: " + overlap.name + + " at " + TimeToString(currentTime, TIME_DATE | TIME_SECONDS); + + // + alert.SendAlert(message); + } + } + // + // Overlap Ended + else if (!isActive && wasActive) + { + // + overlap.isActive = false; + overlap.lastEndTime = currentTime; + + // + NotifyOverlapEnd(overlap.type, currentTime); + + // + // Log Alert + if (alert != NULL) + { + // + string message = "Overlap Ended: " + overlap.name + + " at " + TimeToString(currentTime, TIME_DATE | TIME_SECONDS); + + // + alert.SendAlert(message); + } + } + } + // #endregion + + // #region Event Listener Registration ... + /** + * Add Session Start Event Handler + * + * @param handler: TOnSessionStart + */ + void AddOnSessionStartHandler(TOnSessionStart handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add(handler, mOnSessionStartHandlers); + } + + /** + * Add Session End Event Handler + * + * @param handler: TOnSessionEnd + */ + void AddOnSessionEndHandler(TOnSessionEnd handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add(handler, mOnSessionEndHandlers); + } + + /** + * Add Overlap Start Event Handler + * + * @param handler: TOnOverlapStart + */ + void AddOnOverlapStartHandler(TOnOverlapStart handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add(handler, mOnOverlapStartHandlers); + } + + /** + * Add Overlap End Event Handler + * + * @param handler: TOnOverlapEnd + */ + void AddOnOverlapEndHandler(TOnOverlapEnd handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add(handler, mOnOverlapEndHandlers); + } + + /** + * Add Session State Change Event Handler + * + * @param handler: TOnSessionStateChange + */ + void AddOnSessionStateChangeHandler(TOnSessionStateChange handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add(handler, mOnSessionStateChangeHandlers); + } + // #endregion + + // + protected: + // + + // #region Event Notifiers ... + /** + * Notify Session Start Event + * + * @param session: ENUM_X_SESSION_TYPE + * @param startTime: datetime + */ + void NotifySessionStart( + ENUM_X_SESSION_TYPE session, + datetime startTime // + ) + { + // + // Validate ... + if (!IsXValid(session)) + { + return; + } + + // + // Multiple Handlers ... + int count = ArraySize(mOnSessionStartHandlers); + for (int i = 0; i < count; i++) + { + // + mOnSessionStartHandlers[i]( + session, + startTime // + ); + } + } + + /** + * Notify Session End Event + * + * @param session: ENUM_X_SESSION_TYPE + * @param endTime: datetime + */ + void NotifySessionEnd( + ENUM_X_SESSION_TYPE session, + datetime endTime // + ) + { + // + // Validate ... + if (!IsXValid(session)) + { + return; + } + + // + // Multiple Handlers ... + int count = ArraySize(mOnSessionEndHandlers); + for (int i = 0; i < count; i++) + { + // + mOnSessionEndHandlers[i]( + session, + endTime // + ); + } + } + + /** + * Notify Overlap Start Event + * + * @param overlap: ENUM_X_SESSION_OVERLAP_TYPE + * @param startTime: datetime + */ + void NotifyOverlapStart( + ENUM_X_SESSION_OVERLAP_TYPE overlap, + datetime startTime // + ) + { + // + // Validate ... + if (!IsXValid(overlap)) + { + return; + } + + // + // Multiple Handlers ... + int count = ArraySize(mOnOverlapStartHandlers); + for (int i = 0; i < count; i++) + { + // + mOnOverlapStartHandlers[i]( + overlap, + startTime // + ); + } + } + + /** + * Notify Overlap End Event + * + * @param overlap: ENUM_X_SESSION_OVERLAP_TYPE + * @param endTime: datetime + */ + void NotifyOverlapEnd( + ENUM_X_SESSION_OVERLAP_TYPE overlap, + datetime endTime // + ) + { + // + // Validate ... + if (!IsXValid(overlap)) + { + return; + } + + // + // Multiple Handlers ... + int count = ArraySize(mOnOverlapEndHandlers); + for (int i = 0; i < count; i++) + { + // + mOnOverlapEndHandlers[i]( + overlap, + endTime // + ); + } + } + + /** + * Notify Session State Change Event + * + * @param session: ENUM_X_SESSION_TYPE + * @param state: ENUM_X_SESSION_STATE + */ + void NotifySessionStateChange( + ENUM_X_SESSION_TYPE session, + ENUM_X_SESSION_STATE state // + ) + { + // + // Validate ... + if (!IsXValid(session)) + { + return; + } + + // + // Multiple Handlers ... + int count = ArraySize(mOnSessionStateChangeHandlers); + for (int i = 0; i < count; i++) + { + // + mOnSessionStateChangeHandlers[i]( + session, + state); + } + } + // #endregion + + private: + // +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-account.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCAccount +// Description: provides all Account requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// START Definitions ... +// + +// +// END Definitions ... +// + +// +// START Import and Inclused requirements ... +// + +// +// Includes ... +#include "../Classes/x-saherelm.base.class.mq5" +#include + +// +// END Import and Inclused requirements ... +// + +// +// START Overrides ... +// + +// +// END Overrides ... +// + +// +// a Class for Manage Account ... +class XCAccount : public XCBase +{ + // + // Public ... + public: + // + // Constructor ... + XCAccount() + { + // + mAccountInfo = new CAccountInfo(); + } + + // + // Deconstructor ... + ~XCAccount() + { + } + + // + // START Provided Functions ... + // + + // + // User Account ... + long GetUserAccount() + { + return mAccountInfo.Login(); + } + + // + // Account Leverage ... + long GetLeverage() + { + return mAccountInfo.Leverage(); + } + + // + // Get Trade Expert State ... + bool CanExpertTrade() + { + return mAccountInfo.TradeExpert(); + } + + // + // User Account Trade Mopde (ENUM_ACCOUNT_TRADE_MODE) ... + // -------------------------- + // ACCOUNT_TRADE_MODE_DEMO + // ACCOUNT_TRADE_MODE_CONTEST + // ACCOUNT_TRADE_MODE_REAL + ENUM_ACCOUNT_TRADE_MODE GetTradeMode() + { + return mAccountInfo.TradeMode(); + } + + // + // Get Account Balance ... + double GetBalance() + { + return mAccountInfo.Balance(); + } + + // + // Get the amount of give Credit ... + double GetCredit() + { + return mAccountInfo.Credit(); + } + + // + // Get the amount of current Profit on account ... + double GetProfit() + { + return mAccountInfo.Profit(); + } + + // + // Get the amount of current Equity on account ... + double GetEquity() + { + return mAccountInfo.Equity(); + } + + // + // Get the amount of reserved Margin ... + double GetMargin() + { + return mAccountInfo.Margin(); + } + + // + // Get the amount of free Margin ... + double GetFreeMargin() + { + return mAccountInfo.FreeMargin(); + } + + // + // Get the Level of Margin ... + double GetMarginLevel() + { + return mAccountInfo.MarginLevel(); + } + + // + // Get the Level Of Margin for a Deposit ... + double GetMarginCall() + { + return mAccountInfo.MarginCall(); + } + + // + // Get the Level of Margin for Stop out ... + double GetMarginStopOut() + { + return mAccountInfo.MarginStopOut(); + } + + // + // Get the Client Name ... + string GetName() + { + return mAccountInfo.Name(); + } + + // + // Get the Trade Server Name ... + string GetServerName() + { + return mAccountInfo.Server(); + } + + // + // Get deposit Currency Name ... + string GetCurrency() + { + return mAccountInfo.Currency(); + } + + // + // Get the Company Name that serves an Account ... + string GetCompany() + { + return mAccountInfo.Company(); + } + + // + // Calculate Profits for the current account based on passed parameters ... + double CalculateTradeProfit( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry, // open price + double exit // close price + ) + { + // + double result = mAccountInfo.OrderProfitCheck( + symbol, + type, + volume, + entry, + exit); + + // + return result; + } + + // + // Calculate amount of margin which required for trade operation ... + double CalculateMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.MarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate amount of free margin left after trade operation ... + double CalculateFreeMarging( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double volume, // volume + double entry // open price + ) + { + // + double result = mAccountInfo.FreeMarginCheck( + symbol, + type, + volume, + entry); + + // + return result; + } + + // + // Calculate the Maximum possible volume of trade operation ... + double CalculateMaxVolume( + const string symbol, // trading symbol + ENUM_ORDER_TYPE type, // order type + double entry, // open price + double percent = 100 // percent of available margin + ) + { + // + double result = mAccountInfo.MaxLotCheck( + symbol, + type, + entry, + percent); + + // + return result; + } + + // + // Calculate Point Value for Given Symbol based on Account ... + double GetPointValue( + string symbol // trading symbol + ) + { + // + double result = 0; + + // + double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); + double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); + double point = SymbolInfoDouble(symbol, SYMBOL_POINT); + + // + double ticksPerPoint = tickSize / point; + + // + result = tickValue / ticksPerPoint; + + // + return result; + } + + // + // Calculate Risk Amount based on account Currency by Providing: + // Points and Volume ... + double CalculateRiskAmount( + string symbol, // trading symbol + double points, // amount of Risk Points + double volume // position Volume + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = pointValue * volume * points; + + // + return result; + } + + // + // Calculate Risk Points based on account Currency by Providing: + // Volume and Amount ... + double CalculateRiskPoints( + string symbol, // trading symbol + double volume, // position Volume + double amount // amount of Risk based on Account Currency + ) + { + // + double result = 0; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * volume); + + // + return result; + } + + // + // Calculate Volume based on account Currency by Providing: + // Amount and Risk Points ... + double CalculateVolume( + string symbol, // trading symbol + double amount, // amount of Risk based on Account Currency + double points // amount of Risk Points + ) + { + // + double result = 0; + + // + points = + points <= 0 + ? 10 + : points; + + // + double pointValue = GetPointValue(symbol); + + // + result = amount / (pointValue * points); + + // + return result; + } + + /** + * Retrieve Specified Message for Report Balance ... + * + * @return ( string ) + */ + string GetBalanceReportMessage() + { + return "Balance: " + ToXString(GetBalance()) + " " + GetCurrency(); + } + + // + // END Provided Functions ... + // + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Account Info ... + CAccountInfo mAccountInfo; +}; + +// +// START Usefull Functions ... +// + +// +// END Usefull Functions ... +// + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-alert.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCAlert +// Description: provides all Alerts requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-data.collector.class.mq5" + +// +// Class Definition ... + +class XCAlert : public XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor ... + XCAlert( + string prefix = "X-Alert", // Alerts Prefixe + bool enableAlerts = true, // Enable Alerts + bool logAlerts = true, // Log Alerts + bool terminalAlerts = false, // Terminal Alerts + bool mailAlerts = false, // Mail Alerts + bool pushAlerts = false, // Push Alerts + bool saveAlerts = false // Save Alerts + ) + { + // + mPrefix = prefix; + mLogAlerts = logAlerts; + mMailAlerts = mailAlerts; + mPushAlerts = pushAlerts; + mSaveAlerts = saveAlerts; + mEnableAlerts = enableAlerts; + mTerminalAlerts = terminalAlerts; + + // + // Normalize Prefix if Not Provided ... + if (!IsValid(mPrefix)) + { + mPrefix = GetTag(); + } + + // + // Initialize Collector ... + collector = new XCDataCollector(); + collector.Path(mPrefix); + } + + // + // Deconstructor ... + ~XCAlert() + { + // + // Cleanup Resources ... + delete collector; + ZeroMemory(collector); + } + + // + // Override ... + string GetTag() override + { + return GetSpecificToken(this); + } + + // #region Properties Getter(s) / Setter(s) ... + // + string GetPrefix() + { + return mPrefix; + } + + // + void SetPrefix(string value) + { + // + mPrefix = value; + collector.Path(mPrefix); + } + + // + bool GetLogAlerts() + { + return mLogAlerts; + } + + // + void SetLogAlerts(bool value) + { + mLogAlerts = value; + } + + // + bool GetEnableAlerts() + { + return mEnableAlerts; + } + + // + void SetEnableAlerts(bool value) + { + mEnableAlerts = value; + } + + // + bool GetSaveAlerts() + { + return mSaveAlerts; + } + + // + void SetSaveAlerts(bool value) + { + mSaveAlerts = value; + } + + // + bool GetPushAlerts() + { + return mPushAlerts; + } + + // + void SetPushAlerts(bool value) + { + mPushAlerts = value; + } + + // + bool GetMailAlerts() + { + return mMailAlerts; + } + + // + void SetMailAlerts(bool value) + { + mMailAlerts = value; + } + + // + bool GetTerminalAlerts() + { + return mTerminalAlerts; + } + + // + void SetTerminalAlerts(bool value) + { + mTerminalAlerts = value; + } + // #endregion + + // #region Tools Funtions ... + + // + // Alerts ... + + // + // Logging an Alert ... + void LogAlert(string message, bool save = true) + { + // + // Validate Args ... + if (!CanLogAlert()) + { + return; + } + + // + message = PrepareMessage(message); + + // + Log(message); + + // + if (save) + { + Save(message); + } + } + + // + // Terminal Alert ... + void TerminalAlert(string message, bool save = true) + { + // + // Validate Args ... + if (!CanTerminalAlert()) + { + return; + } + + // + // Prepare Message ... + message = PrepareMessage(message); + + // Send Terminal Alert ... + Alert(message); + + // + if (save) + { + Save(message); + } + } + + // + // Mail Alert ... + void MailAlert(string message, bool save = true) + { + // + // Validate Args ... + if (!CanMailAlert()) + { + return; + } + + // + // Send Mail Alert ... + SendMail(GetPrefix(), message); + + // + if (save) + { + Save(message); + } + } + + // + // Send Push Notification ... + void PushAlert(string message, bool save = true) + { + // + // Validate Args ... + if (!CanPushAlert()) + { + return; + } + + // + // Prepare Message ... + message = PrepareMessage(message); + + // + // Send Push Notification Alert ... + SendNotification(message); + + // + if (save) + { + Save(message); + } + } + + // + // Send an Alert by Handling all Different Specified + // type's of Alert's if they are Enabled ... + void SendAlert(string message) + { + // + // Handle Log, if Enabled ... + LogAlert(message, false); + + // + // Handle Mail if Enabled ... + MailAlert(message, false); + + // + // Handle Push if Enabled ... + PushAlert(message, false); + + // + // Handle Terminal if Enabled ... + TerminalAlert(message, false); + + // + if (GetEnableAlerts()) + { + Save(message); + } + } + + // + // Logs ... + + // + // Log a Message ... + void Log(string message) + { + // + if (!CanLog()) + { + return; + } + + // + Print(message); + } + void Log(string tag, string message) + { + // + if (!CanLog()) + { + return; + } + + // + Print(GetPrefix(), "_", tag, " > ", message); + } + void LogEmpty() + { + // + if (!CanLog()) + { + return; + } + + // + Print(" "); + } + + // + // Log Specific Array ... + template + void LogArray( + T &array[], // Array to Log + string label = NULL // Array Label + ) + { + // + if (!CanLog()) + { + return; + } + + // + Print(GetPrefix(), ">", (IsValid(label) ? label : "")); + ArrayPrint(array); + } + + // + // Error ... + + // + // Log an Error ... + void LogError( + int error = -1 // Specific Error, if it's equal to -1, use Last Error ... + ) + { + // + if (!CanLog()) + { + return; + } + + // + if (error <= -1) + { + error = GetLastError(); + } + + // + string errorMsg = GetErrorDescription(error); + + // + Log("Error: " + errorMsg); + } + + // + // Retrieve Specified Error Code Description ... + string GetErrorDescription(int err_code) + { + // + string result = ""; + + // + switch (err_code) + { + // + //--- Constant Description + + // + case ERR_SUCCESS: + result = "The operation completed successfully"; + break; + + // + case ERR_INTERNAL_ERROR: + result = "Unexpected internal error"; + break; + + // + case ERR_WRONG_INTERNAL_PARAMETER: + result = "Wrong parameter in the inner call of the client terminal function"; + break; + + // + case ERR_INVALID_PARAMETER: + result = "Wrong parameter when calling the system function"; + break; + + // + case ERR_NOT_ENOUGH_MEMORY: + result = "Not enough memory to perform the system function"; + break; + + // + case ERR_STRUCT_WITHOBJECTS_ORCLASS: + result = "The structure contains objects of strings and/or dynamic arrays and/or structure of such objects and/or classes"; + break; + + // + case ERR_INVALID_ARRAY: + result = "Array of a wrong type, wrong size, or a damaged object of a dynamic array"; + break; + + // + case ERR_ARRAY_RESIZE_ERROR: + result = "Not enough memory for the relocation of an array, or an attempt to change the size of a static array"; + break; + + // + case ERR_STRING_RESIZE_ERROR: + result = "Not enough memory for the relocation of string"; + break; + + // + case ERR_NOTINITIALIZED_STRING: + result = "Not initialized string"; + break; + + // + case ERR_INVALID_DATETIME: + result = "Invalid date and/or time"; + break; + + // + case ERR_ARRAY_BAD_SIZE: + result = "Requested array size exceeds 2 GB"; + break; + + // + case ERR_INVALID_POINTER: + result = "Wrong pointer"; + break; + + // + case ERR_INVALID_POINTER_TYPE: + result = "Wrong type of pointer"; + break; + + // + case ERR_FUNCTION_NOT_ALLOWED: + result = "System function is not allowed to call"; + break; + + // + //--- Charts + + // + case ERR_CHART_WRONG_ID: + result = "Wrong chart ID"; + break; + + // + case ERR_CHART_NO_REPLY: + result = "Chart does not respond"; + break; + + // + case ERR_CHART_NOT_FOUND: + result = "Chart not found"; + break; + + // + case ERR_CHART_NO_EXPERT: + result = "No Expert Advisor in the chart that could handle the event"; + break; + + // + case ERR_CHART_CANNOT_OPEN: + result = "Chart opening error"; + break; + + // + case ERR_CHART_CANNOT_CHANGE: + result = "Failed to change chart symbol and period"; + break; + + // + case ERR_CHART_CANNOT_CREATE_TIMER: + result = "Failed to create timer"; + break; + + // + case ERR_CHART_WRONG_PROPERTY: + result = "Wrong chart property ID"; + break; + + // + case ERR_CHART_SCREENSHOT_FAILED: + result = "Error creating screenshots"; + break; + + // + case ERR_CHART_NAVIGATE_FAILED: + result = "Error navigating through chart"; + break; + + // + case ERR_CHART_TEMPLATE_FAILED: + result = "Error applying template"; + break; + + // + case ERR_CHART_WINDOW_NOT_FOUND: + result = "Subwindow containing the indicator was not found"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_ADD: + result = "Error adding an indicator to chart"; + break; + + // + case ERR_CHART_INDICATOR_CANNOT_DEL: + result = "Error deleting an indicator from the chart"; + break; + + // + case ERR_CHART_INDICATOR_NOT_FOUND: + result = "Indicator not found on the specified chart"; + break; + + // + //--- Graphical Objects + case ERR_OBJECT_ERROR: + result = "Error working with a graphical object"; + break; + + // + case ERR_OBJECT_NOT_FOUND: + result = "Graphical object was not found"; + break; + + // + case ERR_OBJECT_WRONG_PROPERTY: + result = "Wrong ID of a graphical object property"; + break; + + // + case ERR_OBJECT_GETDATE_FAILED: + result = "Unable to get date corresponding to the value"; + break; + + // + case ERR_OBJECT_GETVALUE_FAILED: + result = "Unable to get value corresponding to the date"; + break; + + // + //--- MarketInfo + + // + case ERR_MARKET_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_MARKET_NOT_SELECTED: + result = "Symbol is not selected in MarketWatch"; + break; + + // + case ERR_MARKET_WRONG_PROPERTY: + result = "Wrong identifier of a symbol property"; + break; + + // + case ERR_MARKET_LASTTIME_UNKNOWN: + result = "Time of the last tick is not known (no ticks)"; + break; + + // + case ERR_MARKET_SELECT_ERROR: + result = "Error adding or deleting a symbol in MarketWatch"; + break; + + // + //--- History Access + + // + case ERR_HISTORY_NOT_FOUND: + result = "Requested history not found"; + break; + + // + case ERR_HISTORY_WRONG_PROPERTY: + result = "Wrong ID of the history property"; + break; + + // + //--- Global_Variables + + // + case ERR_GLOBALVARIABLE_NOT_FOUND: + result = "Global variable of the client terminal is not found"; + break; + + // + case ERR_GLOBALVARIABLE_EXISTS: + result = "Global variable of the client terminal with the same name already exists"; + break; + + // + case ERR_MAIL_SEND_FAILED: + result = "Email sending failed"; + break; + + // + case ERR_PLAY_SOUND_FAILED: + result = "Sound playing failed"; + break; + + // + case ERR_MQL5_WRONG_PROPERTY: + result = "Wrong identifier of the program property"; + break; + + // + case ERR_TERMINAL_WRONG_PROPERTY: + result = "Wrong identifier of the terminal property"; + break; + + // + case ERR_FTP_SEND_FAILED: + result = "File sending via ftp failed"; + break; + + // + case ERR_NOTIFICATION_SEND_FAILED: + result = "Error in sending notification"; + break; + + // + //--- Custom Indicator Buffers + + // + case ERR_BUFFERS_NO_MEMORY: + result = "Not enough memory for the distribution of indicator buffers"; + break; + + // + case ERR_BUFFERS_WRONG_INDEX: + result = "Wrong indicator buffer index"; + break; + + // + //--- Custom Indicator Properties + + // + case ERR_CUSTOM_WRONG_PROPERTY: + result = "Wrong ID of the custom indicator property"; + break; + + // + //--- Account + + // + case ERR_ACCOUNT_WRONG_PROPERTY: + result = "Wrong account property ID"; + break; + + // + case ERR_TRADE_WRONG_PROPERTY: + result = "Wrong trade property ID"; + break; + + // + case ERR_TRADE_DISABLED: + result = "Trading by Expert Advisors prohibited"; + break; + + // + case ERR_TRADE_POSITION_NOT_FOUND: + result = "Position not found"; + break; + + // + case ERR_TRADE_ORDER_NOT_FOUND: + result = "Order not found"; + break; + + // + case ERR_TRADE_DEAL_NOT_FOUND: + result = "Deal not found"; + break; + + // + case ERR_TRADE_SEND_FAILED: + result = "Trade request sending failed"; + break; + + // + //--- Indicators + + // + case ERR_INDICATOR_UNKNOWN_SYMBOL: + result = "Unknown symbol"; + break; + + // + case ERR_INDICATOR_CANNOT_CREATE: + result = "Indicator cannot be created"; + break; + + // + case ERR_INDICATOR_NO_MEMORY: + result = "Not enough memory to add the indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_APPLY: + result = "The indicator cannot be applied to another indicator"; + break; + + // + case ERR_INDICATOR_CANNOT_ADD: + result = "Error applying an indicator to chart"; + break; + + // + case ERR_INDICATOR_DATA_NOT_FOUND: + result = "Requested data not found"; + break; + + // + case ERR_INDICATOR_WRONG_HANDLE: + result = "Wrong indicator handle"; + break; + + // + case ERR_INDICATOR_WRONG_PARAMETERS: + result = "Wrong number of parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_PARAMETERS_MISSING: + result = "No parameters when creating an indicator"; + break; + + // + case ERR_INDICATOR_CUSTOM_NAME: + result = "The first parameter in the array must be the name of the custom indicator"; + break; + + // + case ERR_INDICATOR_PARAMETER_TYPE: + result = "Invalid parameter type in the array when creating an indicator"; + break; + + // + case ERR_INDICATOR_WRONG_INDEX: + result = "Wrong index of the requested indicator buffer"; + break; + + // + //--- Depth of Market + + // + case ERR_BOOKS_CANNOT_ADD: + result = "Depth Of Market can not be added"; + break; + + // + case ERR_BOOKS_CANNOT_DELETE: + result = "Depth Of Market can not be removed"; + break; + + // + case ERR_BOOKS_CANNOT_GET: + result = "The data from Depth Of Market can not be obtained"; + break; + + // + case ERR_BOOKS_CANNOT_SUBSCRIBE: + result = "Error in subscribing to receive new data from Depth Of Market"; + break; + + // + //--- File Operations + + // + case ERR_TOO_MANY_FILES: + result = "More than 64 files cannot be opened at the same time"; + break; + + // + case ERR_WRONG_FILENAME: + result = "Invalid file name"; + break; + + // + case ERR_TOO_LONG_FILENAME: + result = "Too long file name"; + break; + + // + case ERR_CANNOT_OPEN_FILE: + result = "File opening error"; + break; + + // + case ERR_FILE_CACHEBUFFER_ERROR: + result = "Not enough memory for cache to read"; + break; + + // + case ERR_CANNOT_DELETE_FILE: + result = "File deleting error"; + break; + + // + case ERR_INVALID_FILEHANDLE: + result = "A file with this handle was closed, or was not opening at all"; + break; + + // + case ERR_WRONG_FILEHANDLE: + result = "Wrong file handle"; + break; + + // + case ERR_FILE_NOTTOWRITE: + result = "The file must be opened for writing"; + break; + + // + case ERR_FILE_NOTTOREAD: + result = "The file must be opened for reading"; + break; + + // + case ERR_FILE_NOTBIN: + result = "The file must be opened as a binary one"; + break; + + // + case ERR_FILE_NOTTXT: + result = "The file must be opened as a text"; + break; + + // + case ERR_FILE_NOTTXTORCSV: + result = "The file must be opened as a text or CSV"; + break; + + // + case ERR_FILE_NOTCSV: + result = "The file must be opened as CSV"; + break; + + // + case ERR_FILE_READERROR: + result = "File reading error"; + break; + + // + case ERR_FILE_BINSTRINGSIZE: + result = "String size must be specified, because the file is opened as binary"; + break; + + // + case ERR_INCOMPATIBLE_FILE: + result = "A text file must be for string arrays, for other arrays - binary"; + break; + + // + case ERR_FILE_IS_DIRECTORY: + result = "This is not a file, this is a directory"; + break; + + // + case ERR_FILE_NOT_EXIST: + result = "File does not exist"; + break; + + // + case ERR_FILE_CANNOT_REWRITE: + result = "File can not be rewritten"; + break; + + // + case ERR_WRONG_DIRECTORYNAME: + result = "Wrong directory name"; + break; + + // + case ERR_DIRECTORY_NOT_EXIST: + result = "Directory does not exist"; + break; + + // + case ERR_FILE_ISNOT_DIRECTORY: + result = "This is a file, not a directory"; + break; + + // + case ERR_CANNOT_DELETE_DIRECTORY: + result = "The directory cannot be removed"; + break; + + // + case ERR_CANNOT_CLEAN_DIRECTORY: + result = "Failed to clear the directory (probably one or more files are blocked and removal operation failed)"; + break; + + // + case ERR_FILE_WRITEERROR: + result = "Failed to write a resource to a file"; + break; + + // + //--- String Casting + + // + case ERR_NO_STRING_DATE: + result = "No date in the string"; + break; + + // + case ERR_WRONG_STRING_DATE: + result = "Wrong date in the string"; + break; + + // + case ERR_WRONG_STRING_TIME: + result = "Wrong time in the string"; + break; + + // + case ERR_STRING_TIME_ERROR: + result = "Error converting string to date"; + break; + + // + case ERR_STRING_OUT_OF_MEMORY: + result = "Not enough memory for the string"; + break; + + // + case ERR_STRING_SMALL_LEN: + result = "The string length is less than expected"; + break; + + // + case ERR_STRING_TOO_BIGNUMBER: + result = "Too large number, more than ULONG_MAX"; + break; + + // + case ERR_WRONG_FORMATSTRING: + result = "Invalid format string"; + break; + + // + case ERR_TOO_MANY_FORMATTERS: + result = "Amount of format specifiers more than the parameters"; + break; + + // + case ERR_TOO_MANY_PARAMETERS: + result = "Amount of parameters more than the format specifiers"; + break; + + // + case ERR_WRONG_STRING_PARAMETER: + result = "Damaged parameter of string type"; + break; + + // + case ERR_STRINGPOS_OUTOFRANGE: + result = "Position outside the string"; + break; + + // + case ERR_STRING_ZEROADDED: + result = "0 added to the string end, a useless operation"; + break; + + // + case ERR_STRING_UNKNOWNTYPE: + result = "Unknown data type when converting to a string"; + break; + + // + case ERR_WRONG_STRING_OBJECT: + result = "Damaged string object"; + break; + + // + //--- Operations with Arrays + + // + case ERR_INCOMPATIBLE_ARRAYS: + result = "Copying incompatible arrays. String array can be copied only to a string array, and a numeric array - in numeric array only"; + break; + + // + case ERR_SMALL_ASSERIES_ARRAY: + result = "The receiving array is declared as AS_SERIES, and it is of insufficient size"; + break; + + // + case ERR_SMALL_ARRAY: + result = "Too small array, the starting position is outside the array"; + break; + + // + case ERR_ZEROSIZE_ARRAY: + result = "An array of zero length"; + break; + + // + case ERR_NUMBER_ARRAYS_ONLY: + result = "Must be a numeric array"; + break; + + // + case ERR_ONEDIM_ARRAYS_ONLY: + result = "Must be a one-dimensional array"; + break; + + // + case ERR_SERIES_ARRAY: + result = "Timeseries cannot be used"; + break; + + // + case ERR_DOUBLE_ARRAY_ONLY: + result = "Must be an array of type double"; + break; + + // + case ERR_FLOAT_ARRAY_ONLY: + result = "Must be an array of type float"; + break; + + // + case ERR_LONG_ARRAY_ONLY: + result = "Must be an array of type long"; + break; + + // + case ERR_INT_ARRAY_ONLY: + result = "Must be an array of type int"; + break; + + // + case ERR_SHORT_ARRAY_ONLY: + result = "Must be an array of type short"; + break; + + // + case ERR_CHAR_ARRAY_ONLY: + result = "Must be an array of type char"; + break; + + // + //--- Operations with OpenCL + + // + case ERR_OPENCL_NOT_SUPPORTED: + result = "OpenCL functions are not supported on this computer"; + break; + + // + case ERR_OPENCL_INTERNAL: + result = "Internal error occurred when running OpenCL"; + break; + + // + case ERR_OPENCL_INVALID_HANDLE: + result = "Invalid OpenCL handle"; + break; + + // + case ERR_OPENCL_CONTEXT_CREATE: + result = "Error creating the OpenCL context"; + break; + + // + case ERR_OPENCL_QUEUE_CREATE: + result = "Failed to create a run queue in OpenCL"; + break; + + // + case ERR_OPENCL_PROGRAM_CREATE: + result = "Error occurred when compiling an OpenCL program"; + break; + + // + case ERR_OPENCL_TOO_LONG_KERNEL_NAME: + result = "Too long kernel name (OpenCL kernel)"; + break; + + // + case ERR_OPENCL_KERNEL_CREATE: + result = "Error creating an OpenCL kernel"; + break; + + // + case ERR_OPENCL_SET_KERNEL_PARAMETER: + result = "Error occurred when setting parameters for the OpenCL kernel"; + break; + + // + case ERR_OPENCL_EXECUTE: + result = "OpenCL program runtime error"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_SIZE: + result = "Invalid size of the OpenCL buffer"; + break; + + // + case ERR_OPENCL_WRONG_BUFFER_OFFSET: + result = "Invalid offset in the OpenCL buffer"; + break; + + // + case ERR_OPENCL_BUFFER_CREATE: + result = "Failed to create and OpenCL buffer"; + break; + + // + //--- User-Defined Errors + default: + result = "UNKNOWN Erro ..."; + break; + } + + // + return result; + } + + // + // Retrieve Specified Error Code Description ... + string GetTradeServerReturnCodeDescription(int return_code) + { + // + string result = ""; + + // + switch (return_code) + { + // + case TRADE_RETCODE_REQUOTE: + result = "Requote"; + break; + + // + case TRADE_RETCODE_REJECT: + result = "Request rejected"; + break; + + // + case TRADE_RETCODE_CANCEL: + result = "Request canceled by trader"; + break; + + // + case TRADE_RETCODE_PLACED: + result = "Order placed"; + break; + + // + case TRADE_RETCODE_DONE: + result = "Request completed"; + break; + + // + case TRADE_RETCODE_DONE_PARTIAL: + result = "Only part of the request was completed"; + break; + + // + case TRADE_RETCODE_ERROR: + result = "Request processing error"; + break; + + // + case TRADE_RETCODE_TIMEOUT: + result = "Request canceled by timeout"; + break; + + // + case TRADE_RETCODE_INVALID: + result = "Invalid request"; + break; + + // + case TRADE_RETCODE_INVALID_VOLUME: + result = "Invalid volume in the request"; + break; + + // + case TRADE_RETCODE_INVALID_PRICE: + result = "Invalid price in the request"; + break; + + // + case TRADE_RETCODE_INVALID_STOPS: + result = "Invalid stops in the request"; + break; + + // + case TRADE_RETCODE_TRADE_DISABLED: + result = "Trade is disabled"; + break; + + // + case TRADE_RETCODE_MARKET_CLOSED: + result = "Market is closed"; + break; + + // + case TRADE_RETCODE_NO_MONEY: + result = "There is not enough money to complete the request"; + break; + + // + case TRADE_RETCODE_PRICE_CHANGED: + result = "Prices changed"; + break; + + // + case TRADE_RETCODE_PRICE_OFF: + result = "There are no quotes to process the request"; + break; + + // + case TRADE_RETCODE_INVALID_EXPIRATION: + result = "Invalid order expiration date in the request"; + break; + + // + case TRADE_RETCODE_ORDER_CHANGED: + result = "Order state changed"; + break; + + // + case TRADE_RETCODE_TOO_MANY_REQUESTS: + result = "Too frequent requests"; + break; + + // + case TRADE_RETCODE_NO_CHANGES: + result = "No changes in request"; + break; + + // + case TRADE_RETCODE_SERVER_DISABLES_AT: + result = "Autotrading disabled by server"; + break; + + // + case TRADE_RETCODE_CLIENT_DISABLES_AT: + result = "Autotrading disabled by client terminal"; + break; + + // + case TRADE_RETCODE_LOCKED: + result = "Request locked for processing"; + break; + + // + case TRADE_RETCODE_FROZEN: + result = "Order or position frozen"; + break; + + // + case TRADE_RETCODE_INVALID_FILL: + result = "Invalid order filling type"; + break; + + // + case TRADE_RETCODE_CONNECTION: + result = "No connection with the trade server"; + break; + + // + case TRADE_RETCODE_ONLY_REAL: + result = "Operation is allowed only for live accounts"; + break; + + // + case TRADE_RETCODE_LIMIT_ORDERS: + result = "The number of pending orders has reached the limit"; + break; + + // + case TRADE_RETCODE_LIMIT_VOLUME: + result = "The volume of orders and positions for the symbol has reached the limit"; + break; + + // + default: + result = "Invalid return code of the trade server"; + break; + } + + // + return result; + } + // #endregion + + // + // Protected ... + protected: + // + // Private ... + + // + bool CanLog() + { + return mLogAlerts; + } + + // + bool CanLogAlert() + { + // + bool result = GetEnableAlerts() && GetLogAlerts(); + + // + return result; + } + + // + bool CanTerminalAlert() + { + // + bool result = GetEnableAlerts() && GetTerminalAlerts(); + + // + return result; + } + + // + bool CanMailAlert() + { + // + bool result = GetEnableAlerts() && GetMailAlerts(); + + // + return result; + } + + // + bool CanPushAlert() + { + // + bool result = GetEnableAlerts() && GetPushAlerts(); + + // + return result; + } + + // + void Save(string message) + { + // + if (!mSaveAlerts || + !IsValid(message) || + message == mLastSavedMessage || + PrepareMessage(message) == mLastSavedMessage) + { + return; + } + + // + string fileName = mPrefix + "." + "XLogs"; + string filePath = collector.GetFilePath(fileName); + if (!IsValid(filePath)) + { + return; + } + + // + // Attach Time ... + string savedMessage = ToXString(TimeCurrent()) + " " + message; + + // + bool has = collector.Append( + filePath, + savedMessage // + ); + if (has) + { + mLastSavedMessage = message; + } + } + + private: + // + // Props ... + string mPrefix; // Alerts Prefixe + bool mEnableAlerts; // Enable Alerts + bool mSaveAlerts; // Save Alerts + bool mLogAlerts; // Log Alerts + bool mTerminalAlerts; // Terminal Alerts + bool mMailAlerts; // Mail Alerts + bool mPushAlerts; // Push Alerts + + // + string mLastSavedMessage; // For Prevent Multiple Saving Same Mesage ... + XCDataCollector *collector; + + // + // Tools ... + + // + // Clear Escape String and + // Attach Alert Prefix to Message ... + string PrepareMessage(string message) + { + // + StringReplace(message, "\n", " | "); + + // + StringConcatenate(message, GetPrefix(), " > ", message); + + // + return message; + } +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-app-dialog.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCPanel +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... + +// +#include + +// +#include "../Classes/x-saherelm.base.class.mq5" + +// +// Extentions ... + +/** + * Check a Qery Contains in a Content or not ... + * + * @param mQuery: String ... + * @param mContent: String ... + * @param ignoreCase: Boolean ... + * + * @return ( bool ) + */ +bool XContains( + string mQuery, // Search String + string mContent, // Search Content + bool ignoreCase = true // Ignore Case +) +{ + return Contains( + mQuery, + mContent, + ignoreCase // + ); +} + +// +// Implementation ... + +// +// a Base App Dialog Class ... +class XCAppDialog : public CAppDialog +{ + public: + // + // Action ... + + // + // Virual ... + + /** + * Override Close Button Click Action ... + */ + void OnClickButtonClose() + { + // + bool isClosed = ConfirmDialog("Close EA ?"); + + // + if (isClosed) + { + Destroy(); + } + } + + // + // Configuration Actions ... + + /** + * Show or Hide Minimize Button ... + * + * @param show: boolean + */ + void MinimizeButton(bool show) + { + // + int controlIDX = ControlFind("MinMax"); + if (!IsValidIndex(controlIDX)) + { + return; + } + + // + if (show) + { + Control(controlIDX).Show(); + } + else + { + Control(controlIDX).Hide(); + } + } + + /** + * Show or Hide Close Button ... + * + * @param show: boolean + */ + void CloseButton(bool show) + { + // + int controlIDX = ControlFind("Close"); + if (!IsValidIndex(controlIDX)) + { + return; + } + + // + if (show) + { + Control(controlIDX).Show(); + } + else + { + Control(controlIDX).Hide(); + } + } + + /** + * Minimize Functionality Implementation ... + */ + void Minimize() + { + // + m_minimized = true; + Rebound(m_min_rect); + ClientAreaVisible(false); + } + + /** + * Set Background Color ... + * + * @param clr: Color ... + */ + void BackgroundColor(color clr) + { + // + int controlIDX = ControlFind("Client"); + if (!IsValidIndex(controlIDX)) + { + return; + } + + // + CWnd *obj = Control(controlIDX); + CWndClient *wndclient = (CWndClient *)obj; + + // + wndclient.ColorBackground(clr); + } + + // + // Overrides ... + + // + protected: + // + + /** + * Find Specific Control in Dialog ... + * + * @param name: String to Search + * + * @return ( int ) + */ + int ControlFind(string name) + { + // + int result = -1; + + // + if (!IsValid(name)) + { + return result; + } + + // + int count = ControlsTotal(); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + string iName = Control(i).Name(); + + // + bool isContains = XContains( + name, + iName, + true // Ignore Case ... + ); + if (isContains) + { + // + result = i; + break; + } + } + + // + return result; + } + + /** + * Create and Run Confirm Dialog ... + * + * @param message: message for Message Box ... + * + * @return ( bool ) + */ + bool ConfirmDialog(string message = NULL) + { + // + bool result = false; + + // + if (!IsValid(message)) + { + message = "Confirm ?"; + } + + // + int dialogResult = MessageBox(message, NULL, MB_YESNO); + + // + // use 'switch' or 'if' as needed + switch (dialogResult) + { + // + // Yes ... + case IDYES: + result = true; + break; + // + // No ... + case IDNO: + result = false; + break; + // + // Cancel ... + case IDCANCEL: + result = false; + break; + } + + // + return result; + } + + // + private: + // + + // +}; + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-backtester.expert.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCBackTesterEA +// Description: Back Tester Expert Class ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-chart.helper.class.mq5" +#include "../Classes/x-saherelm.x-guard.class.mq5" +#include "../Classes/x-saherelm.x-position.drawer.class.mq5" +#include "../Classes/x-saherelm.x-target.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" +#include "../Classes/x-saherelm.x-volume.class.mq5" + +// +// Import Chart Objects ... +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Definitions ... + +// +// Implementation ... +class XCBackTesterEA : public XCBase +{ + // + // Public ... + public: + // + + // + // Common ... + long eaMagicNumber; // Magic Number + int eaSlippage; // Slippgae + string eaLogSuffix; // Log Suffix + + // + // Symbol / Period ... + string symbol; // Symbol + ENUM_TIMEFRAMES period; // Period + + // + // Volume ... + ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect; // Volume Applying Type + double eaStaticVoluem; // Static Volume + double eaDynamicVolumeStepBalance; // Step of Balance for Increase Volume + double eaDynamicVolumeStepVolume; // Step of Volume Increasing + double eaConstantRiskBalance; // Constant Risk Balance per Trade + double eaConstantPercent; // Constant Percent of Balance Per Trade + double eaConstantBalance; // Constant Balance for Calculations + + // + // Alert ... + bool eaEnableAlerts; // Enable Alerts + bool eaLogAlerts; // Log Alerts + bool eaMailAlerts; // Mail Alerts + bool eaPushAlerts; // Push Alerts + bool eaTerminalAlerts; // Terminal Alerts + + // + // SL/TP Manipulation Props ... + double allowedTPSLStep; // Value for Change TP/SL in Each Step ... + double minAllowedRiskInPoint; // Min Allowed Risk in Point ... + double riskInPoint; // Risk in Point per Trades ... + double riskToRewardRatio; // Risk To Reward per Trades ... + double volume; // Default volume Per Trade ... + + // + XCAlert *eaAlert; // EA Scope Alert Handler ... + XCGuard *eaGuard; // EA Scope Guard Handler ... + XCTrade *eaTrader; // EA Scope Trade Handler ... + XCTarget *eaTarget; // EA Scope Target Manager ... + XCVolume *eaVolume; // EA Scope Volume Manager ... + XCChartHelper *eaChartHelper; // EA Chart Helper ... + XCPositionDrawer *eaPositionDrawer; // EA Scope Position Drawer ... + + // + // Constructor ... + XCBackTesterEA() + { + // + selectedPositionID = 0; + + // + volume = 0.01; + riskInPoint = 50; + allowedTPSLStep = 5; + riskToRewardRatio = 2; + minAllowedRiskInPoint = 10; + } + + // + // Deconstructor ... + ~XCBackTesterEA() + { + } + + // + // Actions / Handlers ... + + // + // Expert Advisor Event Handlers ... + + /** + * Handle Initialization of Expert ... + * + * @return ( bool ) + */ + bool HandleOnInit() + { + // + bool result = false; + + // + // Validate Inputs ... + result = ValidateInputs(); + if (!result) + { + return result; + } + + // + int count = 0; + bool has = false; + + // + // Chart Helper ... + eaChartHelper = new XCChartHelper(); + + // + // Initialize Alert Handler ... + eaAlert = new XCAlert(); + eaAlert.SetPrefix(eaLogSuffix); + eaAlert.SetLogAlerts(eaLogAlerts); + eaAlert.SetMailAlerts(eaMailAlerts); + eaAlert.SetPushAlerts(eaPushAlerts); + eaAlert.SetEnableAlerts(eaEnableAlerts); + eaAlert.SetTerminalAlerts(eaTerminalAlerts); + + // + // Initialize Trader ... + eaTrader = new XCTrade( + eaSlippage, + eaMagicNumber, + 0, + 0, + 0 // + ); + + // + // Trade Handler Attachments ... + + // + // Position Modifiy Event Handlers ... + count = ArraySize(mOnModifyEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnModifyPositionEventHandler(mOnModifyEventHandlers[i]); + } + } + + // + // Position Stop Loss Event Handlers ... + count = ArraySize(mStopLossEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnStopLossEventHandler(mStopLossEventHandlers[i]); + } + } + + // + // Position Take Profit Event Handlers ... + count = ArraySize(mTakeProfitEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnTakeProfitEventHandler(mTakeProfitEventHandlers[i]); + } + } + + // + // Position Force Close Event Handlers ... + count = ArraySize(mOnForceCloseEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnForceClosePositionEventHandler(mOnForceCloseEventHandlers[i]); + } + } + + // + // Deals Changed Event Handlers ... + count = ArraySize(mDealsChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnDealsChangedEventHandler(mDealsChangedEventHandlers[i]); + } + } + + // + // Orders Changed Event Handlers ... + count = ArraySize(mOrdersChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnOrdersChangedEventHandler(mOrdersChangedEventHandlers[i]); + } + } + + // + // Positions Changed Event Handlers ... + count = ArraySize(mPositionsChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnPositionsChangedEventHandler(mPositionsChangedEventHandlers[i]); + } + } + + // + // Trade Changed Event Handlers ... + count = ArraySize(mTradeStateChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnTradeStateChangedEventHandler(mTradeStateChangedEventHandlers[i]); + } + } + + // + // Postion Partially Close Event Handlers ... + count = ArraySize(mOnPartialCloseEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnPartialClosePositionEventHandler(mOnPartialCloseEventHandlers[i]); + } + } + + // + // Signal Executed Event Handlers ... + count = ArraySize(mOnSignalExecutedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnSignalExecutedEventHandler(mOnSignalExecutedEventHandlers[i]); + } + } + + // + // Init Target Managers ... + eaTarget = new XCTarget(eaTrader, eaAlert); + + // + // Initialize Guard Handler ... + eaGuard = new XCGuard( + eaAlert, + eaTrader // + ); + + // + eaVolume = new XCVolume(); + result = eaVolume.Init( + eaVolumeSelect, + eaStaticVoluem, + eaDynamicVolumeStepBalance, + eaDynamicVolumeStepVolume, + eaConstantRiskBalance, + eaConstantPercent, + eaConstantBalance // + ); + if (!result) + { + return result; + } + + // + // Init Position Drawer ... + eaPositionDrawer = new XCPositionDrawer(eaTrader); + + // + // Initial GUI ... + result = InitGUI(); + if (!result) + { + return result; + } + + // + // Normalize Requirements ... + NormalizeProps(); + + // + return result; + } + + /** + * Handle De Initialization of Expert ... + */ + void HandleOnDeInit() + { + // + eaTarget.Destroy(); + delete eaTarget; + ZeroMemory(eaTarget); + + // + if (eaPositionDrawer != NULL) + { + // + eaPositionDrawer.Destroy(); + delete eaPositionDrawer; + ZeroMemory(eaPositionDrawer); + } + + // + delete eaVolume; + ZeroMemory(eaVolume); + + // + delete eaTrader; + ZeroMemory(eaTrader); + + // + delete eaGuard; + ZeroMemory(eaGuard); + + // + SpecifiedClean(mOnModifyEventHandlers); + SpecifiedClean(mStopLossEventHandlers); + SpecifiedClean(mTakeProfitEventHandlers); + SpecifiedClean(mOnForceCloseEventHandlers); + SpecifiedClean(mDealsChangedEventHandlers); + SpecifiedClean(mOrdersChangedEventHandlers); + SpecifiedClean(mOnPartialCloseEventHandlers); + SpecifiedClean(mPositionsChangedEventHandlers); + SpecifiedClean(mTradeStateChangedEventHandlers); + + // + DestroyGUI(); + + // + string message = "DeInitialized Successfully ..."; + eaAlert.SendAlert(message); + + // + delete eaAlert; + ZeroMemory(eaAlert); + } + + /** + * Handle Tick ... + */ + void HandleOnTick() + { + // + UpdateGUI(); + + // + // Managing Targets ... + eaTarget.Manage(); + + // + // Manage Positions Drawings ... + if (eaPositionDrawer != NULL) + { + eaPositionDrawer.Update(); + } + } + + /** + * Handle Trade ... + */ + void HandleOnTrade() + { + eaTrader.HandleOnTrade(); + } + + /** + * Handle Timer ... + */ + void HandleOnTimer() + { + } + + /** + * Handle Chart Event ... + * + * @param id: int, Event id ... + * @param lparam: long, Event Long Parameter ... + * @param dparam: double, Event Double Parameter ... + * @param sparam: string, Event String Parameter ... + */ + void HandleOnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // + ) + { + } + + // + // Validators ... + + /** + * Validate Inputs ... + * + * @return ( bool ) + */ + bool ValidateInputs() + { + // + bool result = false; + + // + // TODO: Handle this ... + result = true; + + // + return result; + } + + // + // Trade Event Handlers ... + + /** + * Handle Stop Loss Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleOnStopLossTriggered(const XDeal &deal) + { + // + // Update Position Buttons ... + UpdatePositionButtons(); + + // + eaTarget.HandleOnStopLossTriggered(deal); + + // + if (eaPositionDrawer != NULL) + { + eaPositionDrawer.HandleStopLossTriggered(deal); + } + } + + /** + * Handle Take Profit Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleOnTakeProfitTriggered(const XDeal &deal) + { + // + // Update Position Buttons ... + UpdatePositionButtons(); + + // + eaTarget.HandleOnTakeProfitTriggered(deal); + + // + if (eaPositionDrawer != NULL) + { + eaPositionDrawer.HandleOnTakeProfitTriggered(deal); + } + } + + /** + * Handle Position Force Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param position: XPosition instance refrence, Triggered Position ... + * @param comment: string, Comment ... + */ + void HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + // + // Update Position Buttons ... + UpdatePositionButtons(); + + // + eaTarget.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); + + // + if (eaPositionDrawer != NULL) + { + // + eaPositionDrawer.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); + } + } + + /** + * Handle Position Partially Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void HandleOnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // + ) + { + } + + /** + * Handle Deals Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void HandleOnDealsChanged(int count) + { + } + + /** + * Handle Orders Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void HandleOnOrdersChanged(int count) + { + } + + /** + * Handle Positions Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void HandleOnPositionsChanged(int count) + { + // + // Update Position Buttons ... + UpdatePositionButtons(); + } + + /** + * Handle Position Modified Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void HandleOnPositionModified( + const ulong ticket, + const double profit, + const string comment // + ) + { + // + if (eaPositionDrawer != NULL) + { + // + eaPositionDrawer.HandleOnPositionModified( + ticket, + profit, + comment // + ); + } + } + + /** + * Handle all Trades States Changed Event ... + * + * @param state: XOnTradeHandlerState instance refrence, Changed Trade State data ... + */ + void HandleOnTradeStateChanged(const XOnTradeHandlerState &state) + { + } + + /** + * Handle New Signal Recieved ... + * + * @param signal: XSignal, reference to recieved Signal ... + */ + void HandleOnSignalTriggered(XSignal &signal) + { + // + // Draw Signal ... + XCSignalObject *iSignalObj = new XCSignalObject(); + bool isCreated = iSignalObj.Create( + eaChartHelper.ChartId(), + 0, + signal, + 3 // + ); + if (isCreated) + { + } + + // + // Handle Volume ... + double iVolume = eaVolume.CalculateVolume(signal); + if (!signal.ignoreEAVolume && + iVolume != signal.volume) + { + signal.volume = iVolume; + } + + // + ENUM_X_SIGNAL_EXECUTION_RESULT result; + bool isExcuted = eaTrader.ExecuteSignal( + signal, + result // + ); + if (isExcuted) + { + } + } + + /** + * Handle Signal Executed Event ... + * + * @param signal: XSignal, reference to Executed Signal ... + */ + void HandleOnSignalExecuted(XSignal &signal) + { + // + eaTarget.AddExecutedSignal(signal); + + // + if (eaPositionDrawer != NULL) + { + eaPositionDrawer.AddExecutedSignal(signal); + } + } + + // + // Props and Setter / Getter (s) ... + + // + // Trade Event Listeners ... + + // + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mStopLossEventHandlers // + ); + } + + // + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTakeProfitEventHandlers // + ); + } + + // + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mDealsChangedEventHandlers // + ); + } + + // + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOrdersChangedEventHandlers // + ); + } + + // + void AddOnModifyPositionEventHandler(TOnModify handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnModifyEventHandlers // + ); + } + + // + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mPositionsChangedEventHandlers // + ); + } + + // + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTradeStateChangedEventHandlers // + ); + } + + // + void AddOnForceClosePositionEventHandler(TOnForceClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnForceCloseEventHandlers // + ); + } + + // + void AddOnPartialClosePositionEventHandler(TOnPartialClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnPartialCloseEventHandlers // + ); + } + + // + // Add New Signal Executed Event Handler ... + void AddOnSignalExecutedEventHandler(TOnSignal handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnSignalExecutedEventHandlers // + ); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + + // + // Trade Event Listeners ... + TOnModify mOnModifyEventHandlers[]; + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + TOnForceClose mOnForceCloseEventHandlers[]; + TOnSignal mOnSignalExecutedEventHandlers[]; + TOnDealsChanged mDealsChangedEventHandlers[]; + TOnOrdersChanged mOrdersChangedEventHandlers[]; + TOnPartialClose mOnPartialCloseEventHandlers[]; + TOnPositionsChanged mPositionsChangedEventHandlers[]; + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + // Object Props ... + + // + string objSuffix; + + // + CButton btnBuy; + CButton btnSell; + CButton btnClose; + CButton btnCloseAll; + CEdit lblPositionId; + + // + CButton lblTP; + CButton lblSL; + CButton btnSLPlus; + CButton btnTPPlus; + CButton btnSLMinus; + CButton btnTPMinus; + CButton btnSLPlusPlus; + CButton btnTPPlusPlus; + CButton btnSLMinusMinus; + CButton btnTPMinusMinus; + + // + CArrayObj posArray; + CButton *btnSelectedPosInfo; + CArrayObj selectedPosInfoArr; + + // + ulong selectedPositionID; + bool showSelectedPositionInfo; + + // + // GUI Event(s) ... + + /** + * Initialize all GUI Requirements for EA ... + * + * @return ( bool ) + */ + bool InitGUI() + { + // + bool result = false; + + // + int subWindow = 0; + ulong chartId = ChartID(); + objSuffix = eaLogSuffix + "_"; + + // + int startX = 5; + int startY = 25; + + // + int defaultGap = 5; + int defaultWidth = 100; + int defaultHeight = 30; + + // + // Buy ... + int btnBuyX1 = startX; + int btnBuyX2 = startX + defaultWidth; + int btnBuyY1 = startY; + int btnBuyY2 = startY + defaultHeight; + string btnBuyName = objSuffix + "BTN_BUY"; + result = btnBuy.Create( + chartId, + btnBuyName, + subWindow, + btnBuyX1, + btnBuyY1, + btnBuyX2, + btnBuyY2 // + ); + if (result) + { + // + // Apply Buy Button Style ... + + // + btnBuy.Text("Buy"); + btnBuy.Color(clrYellow); + btnBuy.ColorBackground(clrGreen); + } + + // + // Sell ... + int btnSellX1 = btnBuyX1 + btnBuyX2; + int btnSellX2 = btnSellX1 + defaultWidth; + int btnSellY1 = btnBuyY1; + int btnSellY2 = btnBuyY2; + string btnSellName = objSuffix + "BTN_SELL"; + result = btnSell.Create( + chartId, + btnSellName, + subWindow, + btnSellX1, + btnSellY1, + btnSellX2, + btnSellY2 // + ); + if (result) + { + // + // Apply Sell Button Style ... + + // + btnSell.Text("Sell"); + btnSell.Color(clrYellow); + btnSell.ColorBackground(clrDarkRed); + } + + // + // LABEL Position ID ... + int lblPositionIdX1 = btnBuyX1; + int lblPositionIdX2 = lblPositionIdX1 + defaultWidth; + int lblPositionIdY1 = btnSellY2 + defaultGap; + int lblPositionIdY2 = lblPositionIdY1 + defaultHeight; + string lblPositionIdName = objSuffix + "LBL_POS_ID"; + result = lblPositionId.Create( + chartId, + lblPositionIdName, + subWindow, + lblPositionIdX1, + lblPositionIdY1, + lblPositionIdX2, + lblPositionIdY2 // + ); + if (result) + { + // + // Apply Label Position ID Style ... + lblPositionId.ReadOnly(true); + lblPositionId.Text("Pos ID: "); + lblPositionId.Color(clrYellow); + lblPositionId.ColorBackground(clrDarkGray); + } + + // + // Close ... + int btnCloseX1 = startX; + int btnCloseX2 = btnCloseX1 + defaultWidth; + int btnCloseY1 = lblPositionIdY2 + defaultGap; + int btnCloseY2 = btnCloseY1 + defaultHeight; + string btnCloseName = objSuffix + "BTN_CLOSE"; + result = btnClose.Create( + chartId, + btnCloseName, + subWindow, + btnCloseX1, + btnCloseY1, + btnCloseX2, + btnCloseY2 // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnClose.Text("Close"); + btnClose.Color(clrYellow); + btnClose.ColorBackground(clrDarkOrange); + } + + // + // Close All ... + int btnCloseAllX1 = btnCloseX2 + defaultGap; + int btnCloseAllX2 = btnCloseAllX1 + defaultWidth; + int btnCloseAllY1 = lblPositionIdY2 + defaultGap; + int btnCloseAllY2 = btnCloseAllY1 + defaultHeight; + string btnCloseAllName = objSuffix + "BTN_CLOSE_ALL"; + result = btnCloseAll.Create( + chartId, + btnCloseAllName, + subWindow, + btnCloseAllX1, + btnCloseAllY1, + btnCloseAllX2, + btnCloseAllY2 // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnCloseAll.Text("Close All"); + btnCloseAll.Color(clrYellow); + btnCloseAll.ColorBackground(clrDarkRed); + } + + // + int minusPlusWidth = 20; + + // + // TP Label ... + int lblTPX1 = btnCloseX1; + int lblTPX2 = lblTPX1 + defaultWidth; + int lblTPY1 = btnCloseY2 + defaultGap; + int lblTPY2 = lblTPY1 + defaultHeight; + string lblTPName = objSuffix + "LBL_TP"; + result = lblTP.Create( + chartId, + lblTPName, + subWindow, + lblTPX1, + lblTPY1, + lblTPX2, + lblTPY2 // + ); + if (result) + { + // + // Apply Style ... + lblTP.Disable(); + lblTP.Text("TP"); + lblTP.Color(clrWhite); + lblTP.ColorBackground(clrGreen); + } + + // + // TP Plus ... + int btnTPPlusX1 = lblTPX1; + int btnTPPlusX2 = btnTPPlusX1 + minusPlusWidth; + int btnTPPlusY1 = lblTPY2 + defaultGap; + int btnTPPlusY2 = btnTPPlusY1 + defaultHeight; + string btnTPPlusName = objSuffix + "BTN_TP_PLUS"; + result = btnTPPlus.Create( + chartId, + btnTPPlusName, + subWindow, + btnTPPlusX1, + btnTPPlusY1, + btnTPPlusX2, + btnTPPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPPlus.Text("+"); + btnTPPlus.Color(clrYellow); + btnTPPlus.ColorBackground(clrGreen); + } + + // + // TP Plus Plus ... + int btnTPPlusPlusX1 = btnTPPlusX2 + defaultGap; + int btnTPPlusPlusX2 = btnTPPlusPlusX1 + minusPlusWidth; + int btnTPPlusPlusY1 = lblTPY2 + defaultGap; + int btnTPPlusPlusY2 = btnTPPlusPlusY1 + defaultHeight; + string btnTPPlusPlusName = objSuffix + "BTN_TP_PLUSPLUS"; + result = btnTPPlusPlus.Create( + chartId, + btnTPPlusPlusName, + subWindow, + btnTPPlusPlusX1, + btnTPPlusPlusY1, + btnTPPlusPlusX2, + btnTPPlusPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPPlusPlus.Text("++"); + btnTPPlusPlus.Color(clrYellow); + btnTPPlusPlus.ColorBackground(clrGreen); + } + + // + // TP Minus ... + int btnTPMinusX1 = lblTPX2 - minusPlusWidth; + int btnTPMinusX2 = btnTPMinusX1 + minusPlusWidth; + int btnTPMinusY1 = lblTPY2 + defaultGap; + int btnTPMinusY2 = btnTPMinusY1 + defaultHeight; + string btnTPMinusName = objSuffix + "BTN_TP_MINUS"; + result = btnTPMinus.Create( + chartId, + btnTPMinusName, + subWindow, + btnTPMinusX1, + btnTPMinusY1, + btnTPMinusX2, + btnTPMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPMinus.Text("-"); + btnTPMinus.Color(clrYellow); + btnTPMinus.ColorBackground(clrDarkRed); + } + + // + // TP Minus Minus ... + int btnTPMinusMinusX1 = btnTPMinusX1 - minusPlusWidth - defaultGap; + int btnTPMinusMinusX2 = btnTPMinusMinusX1 + minusPlusWidth; + int btnTPMinusMinusY1 = lblTPY2 + defaultGap; + int btnTPMinusMinusY2 = btnTPMinusY1 + defaultHeight; + string btnTPMinusMinusName = objSuffix + "BTN_TP_MINUSMINUS"; + result = btnTPMinusMinus.Create( + chartId, + btnTPMinusMinusName, + subWindow, + btnTPMinusMinusX1, + btnTPMinusMinusY1, + btnTPMinusMinusX2, + btnTPMinusMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPMinusMinus.Text("--"); + btnTPMinusMinus.Color(clrYellow); + btnTPMinusMinus.ColorBackground(clrDarkRed); + } + + // + // SL Label ... + int lblSLX1 = btnCloseAllX1; + int lblSLX2 = lblSLX1 + defaultWidth; + int lblSLY1 = btnCloseAllY2 + defaultGap; + int lblSLY2 = lblTPY1 + defaultHeight; + string lblSLName = objSuffix + "LBL_SL"; + result = lblSL.Create( + chartId, + lblSLName, + subWindow, + lblSLX1, + lblSLY1, + lblSLX2, + lblSLY2 // + ); + if (result) + { + // + // Apply Style ... + lblSL.Disable(); + lblSL.Text("SL"); + lblSL.Color(clrWhite); + lblSL.ColorBackground(clrDarkRed); + } + + // + // SL Plus ... + int btnSLPlusX1 = lblSLX1; + int btnSLPlusX2 = btnSLPlusX1 + minusPlusWidth; + int btnSLPlusY1 = lblSLY2 + defaultGap; + int btnSLPlusY2 = btnSLPlusY1 + defaultHeight; + string btnSLPlusName = objSuffix + "BTN_SL_PLUS"; + result = btnSLPlus.Create( + chartId, + btnSLPlusName, + subWindow, + btnSLPlusX1, + btnSLPlusY1, + btnSLPlusX2, + btnSLPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLPlus.Text("+"); + btnSLPlus.Color(clrYellow); + btnSLPlus.ColorBackground(clrGreen); + } + + // + // SL Plus Plus ... + int btnSLPlusPlusX1 = btnSLPlusX2 + defaultGap; + int btnSLPlusPlusX2 = btnSLPlusPlusX1 + minusPlusWidth; + int btnSLPlusPlusY1 = lblSLY2 + defaultGap; + int btnSLPlusPlusY2 = btnSLPlusPlusY1 + defaultHeight; + string btnSLPlusPlusName = objSuffix + "BTN_SL_PLUSPLUS"; + result = btnSLPlusPlus.Create( + chartId, + btnSLPlusPlusName, + subWindow, + btnSLPlusPlusX1, + btnSLPlusPlusY1, + btnSLPlusPlusX2, + btnSLPlusPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLPlusPlus.Text("++"); + btnSLPlusPlus.Color(clrYellow); + btnSLPlusPlus.ColorBackground(clrGreen); + } + + // + // SL Minus ... + int btnSLMinusX1 = lblSLX2 - minusPlusWidth; + int btnSLMinusX2 = btnSLMinusX1 + minusPlusWidth; + int btnSLMinusY1 = lblSLY2 + defaultGap; + int btnSLMinusY2 = btnSLMinusY1 + defaultHeight; + string btnSLMinusName = objSuffix + "BTN_SL_MINUS"; + result = btnSLMinus.Create( + chartId, + btnSLMinusName, + subWindow, + btnSLMinusX1, + btnSLMinusY1, + btnSLMinusX2, + btnSLMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLMinus.Text("-"); + btnSLMinus.Color(clrYellow); + btnSLMinus.ColorBackground(clrDarkRed); + } + + // + // SL Minus Minus ... + int btnSLMinusMinusX1 = btnSLMinusX1 - minusPlusWidth - defaultGap; + int btnSLMinusMinusX2 = btnSLMinusMinusX1 + minusPlusWidth; + int btnSLMinusMinusY1 = lblSLY2 + defaultGap; + int btnSLMinusMinusY2 = btnSLMinusY1 + defaultHeight; + string btnSLMinusMinusName = objSuffix + "BTN_SL_MINUSMINUS"; + result = btnSLMinusMinus.Create( + chartId, + btnSLMinusMinusName, + subWindow, + btnSLMinusMinusX1, + btnSLMinusMinusY1, + btnSLMinusMinusX2, + btnSLMinusMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLMinusMinus.Text("--"); + btnSLMinusMinus.Color(clrYellow); + btnSLMinusMinus.ColorBackground(clrDarkRed); + } + + // + UpdateGUIState(); + + // + return result; + } + + /** + * Update GUI based on Each Ticks ... + */ + void UpdateGUI() + { + // + UpdateGUIState(); + + // + // Buy Button Pressed ... + if (btnBuy.Pressed()) + { + // + HandleBuyTrade(); + btnBuy.Pressed(false); + } + + // + // Sell Button Pressed ... + if (btnSell.Pressed()) + { + // + HandleSellTrade(); + btnSell.Pressed(false); + } + + // + // Close Button Pressed ... + if (btnClose.Pressed()) + { + // + if (btnClose.IsEnabled()) + { + // + if (selectedPositionID > 0) + { + HandleCloseTrade(selectedPositionID); + } + } + + // + btnClose.Pressed(false); + } + + // + // Close All Button Pressed ... + if (btnCloseAll.Pressed()) + { + // + if (btnCloseAll.IsEnabled()) + { + HandleCloseTrade(0); + } + + // + btnCloseAll.Pressed(false); + } + + // + // Check Show Hide Selected Position Info ... + if (btnSelectedPosInfo != NULL) + { + // + if (btnSelectedPosInfo.Pressed()) + { + // + // Check Enable ... + if (btnSelectedPosInfo.IsEnabled()) + { + // + // Handle Toggle Show/Hide lblSelectedPositionInfo ... + CEdit *iLbl = NULL; + bool isVisible = showSelectedPositionInfo; + int count = selectedPosInfoArr.Total(); + if (IsValidSize(count)) + { + // + // Loop Through Labels ... + for (int i = 0; i < count; i++) + { + // + iLbl = (CEdit *)selectedPosInfoArr.At(i); + isVisible = iLbl.IsVisible(); + if (isVisible) + { + iLbl.Hide(); + } + else + { + iLbl.Show(); + } + } + + // + // Update Button Text ... + isVisible = showSelectedPositionInfo; + string btnText = isVisible + ? "Hide Info" + : "Show Info"; + btnSelectedPosInfo.Text(btnText); + showSelectedPositionInfo = !showSelectedPositionInfo; + } + + // + ZeroMemory(iLbl); + } + + // + btnSelectedPosInfo.Pressed(false); + } + } + + // + // TP Managing ... + + // + // TP Plus ... + if (btnTPPlus.Pressed()) + { + // + if (btnTPPlus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BULLISH); + } + + // + btnTPPlus.Pressed(false); + } + + // + // TP Plus Plus ... + if (btnTPPlusPlus.Pressed()) + { + // + if (btnTPPlusPlus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BULLISH, 2); + } + + // + btnTPPlusPlus.Pressed(false); + } + + // + // TP Minus ... + if (btnTPMinus.Pressed()) + { + // + if (btnTPMinus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BEARISH); + } + + // + btnTPMinus.Pressed(false); + } + + // + // TP Minus Minus ... + if (btnTPMinusMinus.Pressed()) + { + // + if (btnTPMinusMinus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BEARISH, 2); + } + + // + btnTPMinusMinus.Pressed(false); + } + + // + // SL Managing ... + + // + // SL Plus ... + if (btnSLPlus.Pressed()) + { + // + if (btnSLPlus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BULLISH); + } + + // + btnSLPlus.Pressed(false); + } + + // + // SL Plus Plus ... + if (btnSLPlusPlus.Pressed()) + { + // + if (btnSLPlusPlus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BULLISH, 2); + } + + // + btnSLPlusPlus.Pressed(false); + } + + // + // SL Minus ... + if (btnSLMinus.Pressed()) + { + // + if (btnSLMinus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BEARISH); + } + + // + btnSLMinus.Pressed(false); + } + + // + // SL Minus Minus ... + if (btnSLMinusMinus.Pressed()) + { + // + if (btnSLMinusMinus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BEARISH, 2); + } + + // + btnSLMinusMinus.Pressed(false); + } + + // + // Check Positions Buttons ... + int posCount = posArray.Total(); + bool has = IsValidSize(posCount); + if (has) + { + // + for (int i = 0; i < posCount; i++) + { + // + CButton *iBtn = (CButton *)posArray.At(i); + + // + if (iBtn.Pressed()) + { + // + if (iBtn.IsEnabled()) + { + // + ulong posID = ExtractPositionIDFromButtonName(iBtn.Name()); + if (posID > 0 && selectedPositionID != posID) + { + selectedPositionID = posID; + UpdateGUIState(); + } + } + + // + iBtn.Pressed(false); + } + + // + ZeroMemory(iBtn); + } + } + } + + /** + * Destroy all Initialized GUi Requirements ... + */ + void DestroyGUI() + { + // + delete eaChartHelper; + ZeroMemory(eaChartHelper); + + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + + /** + * Update GUI Element Styles ... + */ + void UpdateGUIState() + { + // + // Update States Of Position Select Buttons ... + int count = posArray.Total(); + bool has = IsValidSize(count) && selectedPositionID > 0; + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + CButton *iBtn = (CButton *)posArray.At(i); + + // + ulong posID = ExtractPositionIDFromButtonName(iBtn.Name()); + + // + // Select Position ... + XPosition iPos; + bool hasPosition = eaTrader.GetPosition( + posID, + iPos // + ); + string iTooltip = + !hasPosition + ? "" + : IsLong(iPos.type) + ? "Long" + : "Short"; + + // + if (posID == selectedPositionID) + { + // + iBtn.Disable(); + iBtn.ColorBackground(clrDarkGray); + } + else + { + // + iBtn.Enable(); + + // + color iBtnBG = IsLong(iPos.type) + ? clrGreen + : clrDarkRed; + + // + iBtn.ColorBackground(iBtnBG); + } + + // + ZeroMemory(iBtn); + } + } + + // + // Update State of Close All ... + if (has && count > 1) + { + // + btnCloseAll.Enable(); + btnCloseAll.ColorBackground(clrDarkRed); + } + else + { + // + btnCloseAll.Disable(); + btnCloseAll.ColorBackground(clrDarkGray); + } + + // + // Update Selected Position Info Button State ... + if (has) + { + // + // Reading Global Chart Info ... + int subWindow = 0; + int chartWidth = eaChartHelper.Width(); + ulong chartId = eaChartHelper.ChartId(); + + // + // Read Selected Position ... + XPosition selectedPosition; + bool hasPosition = eaTrader.GetPosition( + selectedPositionID, + selectedPosition // + ); + + // + // Read All Positions ... + double profits = 0; + XPosition positions[]; + string positionsInfo = ""; + int positionsCount = eaTrader.GetPositions(positions); + has = IsValidSize(positionsCount); + if (has) + { + // + for (int i = 0; i < positionsCount; i++) + { + profits += positions[i].profit; + } + + // + if (positionsCount > 1) + { + positionsInfo = "Positions Count: " + ToXString(positionsCount) + ", Profits: " + ToXString(profits); + } + } + + // + if (hasPosition) + { + // + // Preparing Position Info ... + string posTicket = "Ticket: " + ToXString(selectedPosition.ticket); + string posType = "Type: " + ToXString(selectedPosition.type); + string posSymbolPeriod = + "Symbol: " + selectedPosition.symbol + ", " + + "Period: " + ToXString(selectedPosition.period); + string posProfit = "Profit: " + ToXString(selectedPosition.profit); + string posRiskToRewardRatio = "RiskToReward: " + ToXString(selectedPosition.GetRiskRewardRatio()); + string accountInfo = + "Balance: " + ToXString(eaTrader.mAccount.GetBalance()) + ", " + + "Equity: " + ToXString(eaTrader.mAccount.GetEquity()); + + // + string posInfos[]; + + // + // Ticket ... + Add( + posTicket, + posInfos // + ); + + // + // Type ... + Add( + posType, + posInfos // + ); + + // + // Symbol Period ... + Add( + posSymbolPeriod, + posInfos // + ); + + // + // Profit ... + Add( + posProfit, + posInfos // + ); + + // + // Risk to Reward Ratio ... + Add( + posRiskToRewardRatio, + posInfos // + ); + + // + // Add Positions Info if Exists ... + if (IsSpecifiedValid(positionsInfo)) + { + // + Add( + positionsInfo, + posInfos // + ); + + // + // Clear Info Array ... + selectedPosInfoArr.Clear(); + } + + // + // Adding Account Info ... + Add( + accountInfo, + posInfos // + ); + + // + // Create Button If Not Exists ... + if (btnSelectedPosInfo == NULL) + { + // + btnSelectedPosInfo = new CButton(); + + // + string name = objSuffix + "BTN_TOOGLE_SPOS_INFO"; + + // + CRect iRect = btnTPPlus.Rect(); + + // + int x1 = iRect.left; + int x2 = x1 + 200 + 5; + + // + int y1 = iRect.bottom + 5; + int y2 = y1 + iRect.Height(); + + // + bool isCreated = btnSelectedPosInfo.Create( + chartId, + name, + subWindow, + x1, + y1, + x2, + y2 // + ); + if (!isCreated) + { + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + else + { + // + // Apply Styles ... + btnSelectedPosInfo.Color(clrYellow); + btnSelectedPosInfo.ColorBackground(clrDarkBlue); + } + } + + // + // Check Btn Exists ... + has = btnSelectedPosInfo != NULL; + if (has) + { + // + int posInfoCount = ArraySize(posInfos); + int lblInfoCount = selectedPosInfoArr.Total(); + has = IsValidSize(lblInfoCount) && lblInfoCount == posInfoCount; + + // + // Create info Labels ... + if (!has) + { + // + selectedPosInfoArr.Clear(); + has = IsValidSize(posInfoCount); + if (has) + { + // + // Creat Info Control ... + + // + string name = objSuffix + "LBL_SPOS_INFO"; + + // + int lblHeight = 25; + int lblWidth = 450; + + // + int startX = chartWidth - lblWidth - 5; + int sizeX = startX + lblWidth; + + // + int startY = 5; + int sizeY = startY + lblHeight; + + // + // Loop through Position Info's Array to Create Label Controls ... + for (int i = 0; i < posInfoCount; i++) + { + // + string iText = posInfos[i]; + string iTextMD5 = ToMD5(iText); + + // + string iName = name + "_" + iTextMD5; + + // + int iX1 = startX; + int iX2 = sizeX; + + // + int iY1 = startY; + int iY2 = startY + lblHeight; + + // + CEdit *iLbl = new CEdit(); + bool isCreated = iLbl.Create( + chartId, + iName, + subWindow, + iX1, + iY1, + iX2, + iY2 // + ); + if (isCreated) + { + // + iLbl.Text(iText); + iLbl.Color(clrYellow); + iLbl.ColorBorder(clrDarkSlateGray); + iLbl.ColorBackground(clrDarkSlateGray); + + // + if (showSelectedPositionInfo) + { + iLbl.Show(); + } + else + { + iLbl.Hide(); + } + + // + selectedPosInfoArr.Add(iLbl); + + // + startY = iY2; + } + } + } + } + + // + // Update Info Labels ... + lblInfoCount = selectedPosInfoArr.Total(); + has = IsValidSize(lblInfoCount); + if (has) + { + // + CEdit *iLbl = NULL; + + // + // Loop Through Infos ... + for (int i = 0; i < lblInfoCount; i++) + { + // + iLbl = (CEdit *)selectedPosInfoArr.At(i); + + // + iLbl.Text(posInfos[i]); + } + + // + bool isVisible = showSelectedPositionInfo; + string btnText = isVisible + ? "Hide Info" + : "Show Info"; + btnSelectedPosInfo.Text(btnText); + + // + ZeroMemory(iLbl); + } + } + + // + ZeroMemory(posInfos); + } + + // + SpecifiedClean(positions); + } + else + { + // + // Toggle Selected Position Btn ... + if (btnSelectedPosInfo != NULL) + { + // + btnSelectedPosInfo.Destroy(); + + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + + // + // Selected Position Lbls ... + selectedPosInfoArr.Clear(); + } + + // + // Update State of BtnClose and BtnClose All ... + if (selectedPositionID == 0) + { + // + btnClose.Disable(); + btnClose.ColorBackground(clrDarkGray); + + // + lblTP.Disable(); + lblTP.ColorBackground(clrDarkGray); + + // + btnTPPlus.Disable(); + btnTPPlus.ColorBackground(clrDarkGray); + + // + btnTPPlusPlus.Disable(); + btnTPPlusPlus.ColorBackground(clrDarkGray); + + // + btnTPMinus.Disable(); + btnTPMinus.ColorBackground(clrDarkGray); + + // + btnTPMinusMinus.Disable(); + btnTPMinusMinus.ColorBackground(clrDarkGray); + + // + lblSL.Disable(); + lblSL.ColorBackground(clrDarkGray); + + // + btnSLPlus.Disable(); + btnSLPlus.ColorBackground(clrDarkGray); + + // + btnSLPlusPlus.Disable(); + btnSLPlusPlus.ColorBackground(clrDarkGray); + + // + btnSLMinus.Disable(); + btnSLMinus.ColorBackground(clrDarkGray); + + // + btnSLMinusMinus.Disable(); + btnSLMinusMinus.ColorBackground(clrDarkGray); + } + else + { + // + btnClose.Enable(); + btnClose.ColorBackground(clrDarkOrange); + + // + lblTP.Enable(); + lblTP.ColorBackground(clrGreen); + + // + btnTPPlus.Enable(); + btnTPPlus.ColorBackground(clrGreen); + + // + btnTPPlusPlus.Enable(); + btnTPPlusPlus.ColorBackground(clrGreen); + + // + btnTPMinus.Enable(); + btnTPMinus.ColorBackground(clrDarkRed); + + // + btnTPMinusMinus.Enable(); + btnTPMinusMinus.ColorBackground(clrDarkRed); + + // + lblSL.Enable(); + lblSL.ColorBackground(clrDarkRed); + + // + btnSLPlus.Enable(); + btnSLPlus.ColorBackground(clrGreen); + + // + btnSLPlusPlus.Enable(); + btnSLPlusPlus.ColorBackground(clrGreen); + + // + btnSLMinus.Enable(); + btnSLMinus.ColorBackground(clrDarkRed); + + // + btnSLMinusMinus.Enable(); + btnSLMinusMinus.ColorBackground(clrDarkRed); + } + } + + /** + * Update Position's Selector Buttons ... + */ + void UpdatePositionButtons() + { + // + // Retrieve Positions ... + XPosition positions[]; + int count = eaTrader.GetPositions( + positions // + ); + bool has = IsValidSize(count); + if (!has) + { + // + posArray.Clear(); + selectedPositionID = 0; + UpdateGUIState(); + return; + } + + // + posArray.Clear(); + + // + // Selected Position ID ... + bool isSelectdPositionIDExists = false; + if (has && selectedPositionID > 0) + { + // + for (int i = 0; i < count; i++) + { + // + if (!isSelectdPositionIDExists && + positions[i].ticket == selectedPositionID) + { + // + isSelectdPositionIDExists = true; + break; + } + } + } + if (!isSelectdPositionIDExists || + selectedPositionID == 0) + { + // + XPosition youngest; + int youngestIDX = GetXYoungest(youngest, positions); + bool hasYoungest = IsValidIndex(youngestIDX) && + youngest.IsValid(); + if (hasYoungest) + { + selectedPositionID = youngest.ticket; + } + + // + youngest.Clean(); + } + + // + int subWindow = 0; + ulong chartId = eaChartHelper.ChartId(); + + // + int btnWidth = 25; + int btnHeight = 25; + + // + CRect iRect = lblPositionId.Rect(); + + // + int lastX = iRect.left + iRect.Width() + 5; + int lastSizeX = lastX + btnWidth; + + // + int lastY = iRect.top; + int lastSizeY = lastY + iRect.Height(); + + // + for (int i = 0; i < count; i++) + { + // + XPosition iPos = positions[i]; + + // + string posTypeStr = IsLong(iPos.type) + ? "LONG" + : "SHORT"; + + // + int iPosBtnX = lastX; + int iPosBtnSizeX = iPosBtnX + btnWidth; + string iPosBtnName = objSuffix + "_" + posTypeStr + "_POS_SELECT_BTN_" + ToXString(iPos.ticket); + + // + CButton *iPosBtn = new CButton(); + has = iPosBtn.Create( + chartId, + iPosBtnName, + subWindow, + iPosBtnX, + lastY, + iPosBtnSizeX, + lastSizeY // + ); + if (has) + { + // + // Apply Styles ... + string iPosBtnText = ToXString(iPos.ticket); + + // + iPosBtn.Text(iPosBtnText); + iPosBtn.Color(clrWhite); + + // + color iPosBtnBG = IsLong(iPos.type) + ? clrGreen + : clrDarkRed; + iPosBtn.ColorBackground(iPosBtnBG); + + // + lastX = iPosBtnSizeX + 5; + + // + if (selectedPositionID == iPos.ticket) + { + iPosBtn.Disable(); + } + + // + posArray.Add(iPosBtn); + } + + // + iPos.Clean(); + } + + // + ZeroMemory(positions); + UpdateGUIState(); + } + + // + // GUI Event Handlers ... + + // + void HandleBuyTrade() + { + HandleTrade(X_DIRECTION_BULLISH); + } + + // + void HandleSellTrade() + { + HandleTrade(X_DIRECTION_BEARISH); + } + + // + void HandleTrade(ENUM_X_DIRECTION dir) + { + // + if (!HasDirection(dir)) + { + return; + } + + // + NormalizeProps(); + + // + bool isBullish = IsSpecifiedBullish(dir); + + // + double r2r = riskToRewardRatio; + double _volume = volume; + double _riskInPoints = riskInPoint; + double point = GetPoints(symbol); + double entry = GetEntry(symbol, dir); + + // + double risk = _riskInPoints * point; + double reward = risk * r2r; + + // + double sl = isBullish + ? entry - risk + : entry + risk; + double tp = isBullish + ? entry + reward + : entry - reward; + + // + string comment = eaLogSuffix + "_POS_" + ToXString(dir); + + // + if (isBullish) + { + // + eaTrader.Buy( + symbol, + period, + _volume, + entry, + sl, + tp, + comment // + ); + } + else + { + // + eaTrader.Sell( + symbol, + period, + _volume, + entry, + sl, + tp, + comment // + ); + } + } + + // + void HandleCloseTrade(ulong positionID) + { + // + if (positionID == 0) + { + // + XPosition positions[]; + int count = eaTrader.GetPositions( + positions // + ); + bool has = IsValidSize(count); + if (has) + { + // + int closedCount = eaTrader.Close(positions); + has = IsValidSize(closedCount); + } + } + else + { + // + XPosition position; + bool has = eaTrader.GetPosition( + positionID, + position // + ); + if (has) + { + // + has = eaTrader.Close(positionID); + } + } + } + + // + void HandleTPChange( + ENUM_X_DIRECTION dir, + int multiplier = 1 // + ) + { + // + // Validate ... + if (selectedPositionID == 0 || !HasDirection(dir)) + { + return; + } + + // + NormalizeProps(); + + // + // Normalize Multiplier ... + multiplier = NormalizeInt(multiplier, 1, 2); + + // + // Select Position ... + XPosition position; + bool has = eaTrader.GetPosition( + selectedPositionID, + position // + ); + if (!has) + { + // + position.Clean(); + return; + } + + // + bool isLong = IsLong(position.type); + bool isBullish = IsSpecifiedBullish(dir); + + // + double point = GetPoints(position.symbol); + double stepValue = multiplier * (point * allowedTPSLStep); + + // + bool mustIncrease = + isBullish + ? isLong + : !isLong; + + // + double tp = position.tp; + tp = + mustIncrease + ? tp + stepValue + : tp - stepValue; + bool isModified = eaTrader.Modify( + position.ticket, + position.sl, + tp, + objSuffix + "Change TP" // + ); + if (isModified) + { + UpdateGUIState(); + } + + // + position.Clean(); + } + + // + void HandleSLChange( + ENUM_X_DIRECTION dir, + int multiplier = 1 // + ) + { + // + // Validate ... + if (selectedPositionID == 0 || !HasDirection(dir)) + { + return; + } + + // + NormalizeProps(); + + // + // Normalize Multiplier ... + multiplier = NormalizeInt(multiplier, 1, 2); + + // + // Select Position ... + XPosition position; + bool has = eaTrader.GetPosition( + selectedPositionID, + position // + ); + if (!has) + { + // + position.Clean(); + return; + } + + // + bool isLong = IsLong(position.type); + bool isBullish = IsSpecifiedBullish(dir); + + // + double point = GetPoints(position.symbol); + double stepValue = multiplier * (point * allowedTPSLStep); + + // + bool mustIncrease = + isBullish + ? !isLong + : isLong; + + // + double risk = position.GetRiskInPoint(); + if (risk <= minAllowedRiskInPoint) + { + // + position.Clean(); + return; + } + + // + double sl = position.sl; + sl = + mustIncrease + ? sl + stepValue + : sl - stepValue; + bool isModified = eaTrader.Modify( + position.ticket, + sl, + position.tp, + objSuffix + "Change SL" // + ); + if (isModified) + { + UpdateGUIState(); + } + + // + position.Clean(); + } + + // + // Custom Tools ... + + // + void NormalizeProps() + { + // + if (volume < 0.01) + { + volume = 0.01; + } + + // + if (riskInPoint < 0) + { + riskInPoint = 50; + } + + // + if (allowedTPSLStep < 5) + { + allowedTPSLStep = 5; + } + + // + if (riskToRewardRatio < 0.5) + { + riskToRewardRatio = 2; + } + + // + if (minAllowedRiskInPoint < 10) + { + minAllowedRiskInPoint = 10; + } + } + + // + ulong ExtractPositionIDFromButtonName(string name) + { + // + ulong result = 0; + + // + string nameParts[]; + int namePartsCount = SplitContent(nameParts, name, "_"); + bool has = IsValidSize(namePartsCount); + if (has) + { + // + string lastPart = nameParts[namePartsCount - 1]; + StringReplace(lastPart, "_", ""); + result = (long)lastPart; + } + + // + ZeroMemory(nameParts); + + // + return result; + } +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-bar.analyser.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XPOI +// Description: Bar Analysing ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Libraries/x-saherelm.x-poi.lib.mq5" + +// +// Definitions ... + +// +// Extensions ... +void FillLiquidity( + XOHCL &lBar, + ENUM_X_DIRECTION lDir, + XBoxZone &lq, + datetime to // +) +{ + // + // Normalize Args ... + lq.Clean(); + to = NormalizeTime(to); + + // + // Validate Args ... + bool has = lBar.IsValid() && + HasDirection(lDir); + if (!has) + { + return; + } + + // + lq.to = to; + lq.dir = lDir; + lq.type = "XLQ"; + lq.from = lBar.time; + lq.symbol = lBar.symbol; + lq.period = lBar.period; + lq.upper = IsBullish(lDir) + ? lBar.GetDown() + : lBar.high; + lq.lower = IsBullish(lDir) + ? lBar.low + : lBar.GetUp(); +} + +// +// Implementations ... +class XCBarAnalyser : public XCBase +{ + // + public: + // + + // + // Constructor(s) ... + XCBarAnalyser() + { + } + + // + // Deconstructor ... + ~XCBarAnalyser() + { + } + + // + // Getter(s) / Setter(s) ... + + // + // Providers ... + + /** + * Calculate Loopback Data for Specific Bar ... + * + * @param index: Integer, Bar Current Index ... + * @param start: Integer, Start of Loopback ... + * @param end: Integer, End of Loopback ... + * @param count: Integer, Number of Calculating Bars ... + * @param bar: XOHCL instance, Specified Bar ... + * @param loopback: Integer, Loopback Length ... + * @return ( bool ) + */ + bool CalculateLoopbackData( + int &index, + int &start, + int &end, + int &count, + XOHCL &bar, + int loopback = 1 // + ) + { + // + bool result = false; + + // + if (loopback < 1) + { + loopback = 1; + } + + // + index = -1; + start = -1; + end = -1; + count = -1; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + index = bar.Index(); + start = index + 1; + end = start + loopback; + count = end - start; + result = count >= 1; + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Retrieve Loopback HH & LL Data ... + * + * @param hhIDX: Integer, HH Index ... + * @param hh: Double, HH Value ... + * @param llIDX: Integer, LL Index ... + * @param ll: Double, LL Value ... + * @param bar: XOHCL instance ... + * @param loopback: Integer, Loopback Length ... + * + * @return ( bool ) + */ + bool CalculateLoopbackHLData( + int &hhIDX, + double &hh, + int &llIDX, + double &ll, + XOHCL &bar, + int loopback // + ) + { + // + bool result = false; + + // + if (loopback < 1) + { + loopback = 1; + } + + // + int index = -1; + int start = -1; + int end = -1; + int count = -1; + result = CalculateLoopbackData( + index, + start, + end, + count, + bar, + loopback // + ); + if (!result) + { + return result; + } + + // + hhIDX = iHighest( + bar.symbol, + bar.period, + MODE_HIGH, + count, + start // + ); + result = IsValidIndex(hhIDX); + if (!result) + { + return result; + } + + // + llIDX = iLowest( + bar.symbol, + bar.period, + MODE_LOW, + count, + start // + ); + result = IsValidIndex(llIDX); + if (!result) + { + return result; + } + + // + hh = iHigh( + bar.symbol, + bar.period, + hhIDX // + ); + ll = iLow( + bar.symbol, + bar.period, + llIDX // + ); + + // + return result; + } + + /** + * Fill Prices ... + * + * @param prices: double collection + * @param bar: XOHCL instance reference, Provides Start ... + * @param loopback: int, Specified How Many Bars Process ... + * @param type: ENUM_X_PRICE member, Specified Price Type ... + * + * @return ( bool ) + */ + int FillPrice( + double &prices[], + XOHCL &bar, + int loopback = 14, + ENUM_X_PRICE type = X_PRICE_CLOSE // + ) + { + // + int result = 0; + + // + Clean(prices); + + // + loopback = NormalizeInt(loopback, 1); + + // + bool has = IsValid(type) && + bar.IsValid(); + if (!has) + { + return result; + } + + // + string symbol = bar.symbol; + ENUM_TIMEFRAMES period = bar.period; + + // + // Calculate Loopback Data ... + int index = -1; + int start = -1; + int end = -1; + int count = -1; + has = CalculateLoopbackData( + index, + start, + end, + count, + bar, + loopback // + ); + if (!has) + { + return result; + } + + // + for (int i = start; i < end; i++) + { + // + XOHCL iBar; + bool isInited = iBar.Init( + symbol, + period, + i // + ); + if (!isInited) + { + // + iBar.Clean(); + continue; + } + + // + double iPrice = iBar.GetPrice(type); + + // + isInited = NotEmptyZero(iPrice); + if (isInited) + { + // + Add( + iPrice, + prices // + ); + } + + // + iBar.Clean(); + } + + // + result = ArraySize(prices); + has = result == count; + if (!has) + { + // + Clean(prices); + } + + // + ArrayReverse(prices); + + // + return result; + } + + /** + * Calculate Price Range ... + * + * @param ranges: double Collection, Calculated Ranges ... + * @param bar: XOHCL instance Reference, Start Bar ... + * @param forceBody: bool, Force to Calculate Range using Body ... + * @param forceDiff: bool, Force to Calculate Range using Onl Price Diff ... + * @param loopback: int, loopback period for Range Calculations ... + * + * @return ( int ) + */ + int GetPriceRange( + double &ranges[], + XOHCL &bar, + bool forceBody = false, + bool forceDiff = false, + int loopback = 14 // + ) + { + // + int result = 0; + + // + Clean(ranges); + + // + loopback = NormalizeInt(loopback, 1); + + // + if (!bar.IsValid()) + { + return result; + } + + // + bool has = false; + + // + // Select Uppers Prices ... + double uppers[]; + int uppersCount = 0; + if (forceBody) + { + // + has = FillPrice( + uppers, + bar, + loopback, + X_PRICE_UP // + ); + } + else + { + // + has = FillPrice( + uppers, + bar, + loopback, + X_PRICE_HIGH // + ); + } + if (has) + { + uppersCount = ArraySize(uppers); + } + + // + // Select Lower Prices ... + double lowers[]; + int lowersCount = 0; + if (forceBody) + { + // + has = FillPrice( + lowers, + bar, + loopback, + X_PRICE_DOWN // + ); + } + else + { + // + has = FillPrice( + lowers, + bar, + loopback, + X_PRICE_LOW // + ); + } + if (has) + { + lowersCount = ArraySize(lowers); + } + + // + // Validate Filled Prices ... + has = + IsValidSize(uppersCount) && + IsValidSize(lowersCount) && + uppersCount == lowersCount; + if (!has) + { + // + Clean(uppers); + Clean(lowers); + + // + return result; + } + + // + for (int i = 0; i < uppersCount; i++) + { + // + double iDiff = uppers[i] - lowers[i]; + double iValue = + forceDiff + ? iDiff + : lowers[i] + iDiff; + + // + Add( + iValue, + ranges // + ); + } + + // + result = ArraySize(ranges); + ArrayReverse(ranges); + + // + // Cleanup Resources ... + + // + Clean(uppers); + Clean(lowers); + + // + return result; + } + + /** + * Retrieve Price Velocities ... + * + * @param velocities: double Collection, Price Velocities ... + * @param bar: XOHCL instance Reference, Start Bar ... + * @param type: ENUM_X_PRICE member ... + * @param loopback: int, loopback period for Calculations ... + * + * @return ( int ) + */ + int GetPriceVelocity( + double &velocities[], + XOHCL &bar, + ENUM_X_PRICE type = X_PRICE_CLOSE, + int loopback = 14 // + ) + { + // + int result = 0; + + // + Clean(velocities); + loopback = NormalizeInt(loopback, 1); + + // + result = IsValid(type) && + bar.IsValid(); + + // + int to = bar.Index(); + int from = to + loopback; + for (int i = to; i < from; i++) + { + // + double iPrice = GetAppliedPrice( + bar.symbol, + bar.period, + i, + type // + ); + + // + double pPrice = GetAppliedPrice( + bar.symbol, + bar.period, + i + 1, + type // + ); + + // + double iVelocity = MathAbs(iPrice - pPrice); + Add( + iVelocity, + velocities // + ); + } + + // + result = ArraySize(velocities); + + // + return result; + } + + /** + * Calculate Price Change Percent ... + * + * @param bar: XOHCL instance Reference, Start Bar ... + * @param type: ENUM_X_PRICE member, Specified Price Type ... + * @param loopback: int, loopback period for Range Calculated ... + * + * @return ( double ) + */ + double GetPriceChangeRate( + XOHCL &bar, + ENUM_X_PRICE type = X_PRICE_MEDIAN, + int loopback = 14 // + ) + { + // + double result = 0; + + // + bool has = false; + + // + loopback = NormalizeInt(loopback, 1); + + // + has = + bar.IsValid() && + IsValid(type); + if (!has) + { + return result; + } + + // + XOHCL oldBar; + has = oldBar.Init( + bar.symbol, + bar.period, + bar.Index() + loopback // + ); + if (!has) + { + // + oldBar.Clean(); + + // + return result; + } + double newPrice = bar.GetPrice(type); + double oldPrice = oldBar.GetPrice(type); + + // + result = ((newPrice - oldPrice) / oldPrice) / 100; + + // + oldBar.Clean(); + + // + return result; + } + + /** + * Detect Range Block ... + */ + bool DetectRangeBlocks( + XOHCL &bar, + XBoxZone &upper, + XBoxZone &lower, + int loopback = 288, + ENUM_SERIESMODE upperRangeUpperMode = MODE_HIGH, + ENUM_SERIESMODE upperRangeLowerMode = MODE_LOW, + ENUM_SERIESMODE lowerRangeUpperMode = MODE_HIGH, + ENUM_SERIESMODE lowerRangeLowerMode = MODE_LOW // + ) + { + // + bool result = false; + + // + // Normalize Args ... + upper.Clean(); + lower.Clean(); + loopback = NormalizeInt(loopback, 10); + + // + // Validate Args ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL iBar; + result = iBar.Init( + bar.symbol, + bar.period, + bar.Index() + loopback // + ); + if (!result) + { + // + iBar.Clean(); + + // + return result; + } + + // + double hhUpper = iBar.FindHighest(loopback, upperRangeUpperMode); + double hhLower = iBar.FindHighest(loopback, upperRangeLowerMode); + + // + double llUpper = iBar.FindLowest(loopback, lowerRangeUpperMode); + double llLower = iBar.FindLowest(loopback, lowerRangeLowerMode); + + // + double bhhUpper = bar.FindHighest(iBar.Index() - bar.Index(), upperRangeUpperMode); + double bhhLower = bar.FindHighest(iBar.Index() - bar.Index(), upperRangeLowerMode); + + // + double bllUpper = bar.FindLowest(iBar.Index() - bar.Index(), lowerRangeUpperMode); + double bllLower = bar.FindLowest(iBar.Index() - bar.Index(), lowerRangeLowerMode); + + // + hhUpper = MathMax(hhUpper, bhhUpper); + hhLower = MathMax(hhLower, bhhLower); + + // + llUpper = MathMin(llUpper, bllUpper); + llLower = MathMin(llLower, bllLower); + + // + datetime from = GetBarTime( + iBar.symbol, + iBar.period, + iBar.Index() + loopback // + ); + + // + upper.from = from; + upper.type = "XRNG"; + upper.to = bar.time; + upper.upper = hhUpper; + upper.lower = hhLower; + upper.symbol = iBar.symbol; + upper.period = iBar.period; + upper.dir = X_DIRECTION_BEARISH; + + // + lower.from = from; + lower.type = "XRNG"; + lower.to = bar.time; + lower.upper = llUpper; + lower.lower = llLower; + lower.symbol = iBar.symbol; + lower.period = iBar.period; + lower.dir = X_DIRECTION_BULLISH; + + // + result = upper.IsValid() && + lower.IsValid(); + if (!result) + { + // + iBar.Clean(); + upper.Clean(); + lower.Clean(); + } + + // + iBar.Clean(); + + // + return result; + } + + /** + * Calculate Specified Bars Range Volume ... + * + * @param bar: XOHCL instance reference ... + * @param bullishVolume: double + * @param bearishVolume: double + * @param loopback: int + * + * @return ( bool ) + */ + bool CalculateRangeVolume( + XOHCL &bar, + double &bullishVolume, + double &bearishVolume, + int loopback = 5 // + ) + { + // + bool result = false; + + // + // Normalize Args ... + bullishVolume = 0; + bearishVolume = 0; + loopback = NormalizeInt(loopback, 3); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL iBar; + bool has = false; + int start = bar.Index(); + int end = start + loopback; + for (int i = start; i <= end; i++) + { + // + iBar.Clean(); + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!has) + { + // + iBar.Clean(); + + // + break; + } + + // + bool isBullish = iBar.IsBullish(); + bool isBearish = iBar.IsBearish(); + + // + if (isBullish) + { + bullishVolume += (double)iBar.volume; + } + else if (isBearish) + { + bearishVolume += (double)iBar.volume; + } + else + { + // + bullishVolume += (double)iBar.volume; + bearishVolume += (double)iBar.volume; + } + + // + iBar.Clean(); + } + + // + result = iBar.IsValid(); + + // + iBar.Clean(); + + // + return result; + } + + /** + * Detect Same Bars ... + * + * @param bar: XOHCL instance, Start Bar ... + * @param dir: ENUM_X_DIRECTION member, Holds Result Direction ... + * @param index: Integer, Holds Result Index ... + * @param sameBars: Iteger, Required Same Bar ... + * + * @return ( bool ) + */ + bool HasSameBars( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int &index, + int sameBars = 3 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + if (sameBars < 1) + { + sameBars = 1; + } + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + index = bar.Index() + 1; + bool canContinue = true; + int sameBullishBarsFounded = 0; + int sameBearishBarsFounded = 0; + bool canContinueForBullish = true; + bool canContinueForBearish = true; + while (canContinue) + { + // + XOHCL iBar; + result = iBar.Init( + bar.symbol, + bar.period, + index // + ); + if (!result) + { + break; + } + + // + bool isBullish = iBar.IsBullish(); + bool isBearish = iBar.IsBearish(); + result = isBullish || + isBearish; + if (!result) + { + break; + } + + // + if (isBullish) + { + // + sameBullishBarsFounded++; + canContinueForBearish = false; + } + else if (isBearish) + { + // + sameBearishBarsFounded++; + canContinueForBullish = false; + } + else + { + // + sameBullishBarsFounded = 0; + sameBearishBarsFounded = 0; + canContinueForBullish = false; + canContinueForBearish = false; + } + + // + result = canContinueForBullish || + canContinueForBearish; + if (!result) + { + break; + } + + // + canContinueForBullish = + canContinueForBullish && + sameBullishBarsFounded > 0; + + // + canContinueForBearish = + canContinueForBearish && + sameBearishBarsFounded > 0; + + // + canContinue = + canContinueForBullish || + canContinueForBearish; + if (canContinue) + { + index++; + } + } + + // + bool hasBullishSameBars = + sameBullishBarsFounded >= sameBars; + + // + bool hasBearishSameBars = + sameBearishBarsFounded >= sameBars; + + // + result = hasBullishSameBars || + hasBearishSameBars; + if (!result) + { + return result; + } + + // + index--; + + // + dir = + hasBullishSameBars + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + /** + * Check Fibonacci Level 382 Pressure ... + * + * @param bar: XOHCL instance ... + * @param dir: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ + bool HasFiboPressure( + XOHCL &bar, + ENUM_X_DIRECTION forDir, + ENUM_X_FIBO_LEVELS level // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsBullish(forDir); + bool isBearish = IsBearish(forDir); + + // + double fiboLevelValue = GetFibonacciLevel( + bar.high, + bar.low, + level, + forDir // + ); + + // + bool isBullishPressured = + isBullish && + bar.GetDown() > fiboLevelValue; + bool isBearishPressured = + isBearish && + bar.GetUp() < fiboLevelValue; + + // + result = isBullishPressured || + isBearishPressured; + + // + return result; + } + + /** + * Detect Big Price Change Happens or not ... + * + * @param bar: XOHCL instance reference, Start Bar ... + * @param dir: ENUM_X_DIRECTION member, Event Direction ... + * @param rootIDX: int, Root of Momentum Index ... + * @param type: ENUM_X_PRICE member, Price Type ... + * @param forcBodyInRange: bool, Use Body in Range Detection ... + * @param rangeExtendMultiplier: double, a Multiplier for Checking Price Range ... + * + * @return ( bool ) + */ + bool IsSharp( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int &rootIDX, + ENUM_X_PRICE type = X_PRICE_CLOSE, + bool forcBodyInRange = true, + double rangeExtendMultiplier = 2.0 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + rangeExtendMultiplier = NormalizeDouble(rangeExtendMultiplier, 1); + + // + result = + bar.IsValid() && + IsValid(type); + if (!result) + { + return result; + } + + // + double minPriceChangePercent = 0; + int loopback = GetPeriodSharpData( + minPriceChangePercent, + bar.period // + ); + + // + // Retrieve Price Change Percent ... + double priceChangePercent = GetPriceChangeRate( + bar, + type, + loopback // + ); + + // + // Velocities ... + double velocities[]; + int velocitiesCount = GetPriceVelocity( + velocities, + bar, + type, + loopback // + ); + double velocitiesAvg = GetAverage(velocities); + double oldPrice = GetAppliedPrice( + bar.symbol, + bar.period, + bar.Index() + loopback, + type // + ); + double newPrice = bar.GetPrice(type); + double currVelocity = MathAbs(oldPrice - newPrice); + + // + // Calculate HH and LL ... + + // + double hh = 0; + double ll = 0; + int hhIDX = -1; + int llIDX = -1; + result = CalculateLoopbackHLData( + hhIDX, + hh, + llIDX, + ll, + bar, + loopback // + ); + result = + result && + ll > 0 && + hh > ll && + IsValidIndex(llIDX) && + IsValidIndex(hhIDX); + if (!result) + { + return result; + } + + // + int hhDiff = (hhIDX - bar.Index()); + int llDiff = (llIDX - bar.Index()); + + // + // Bool Get Boundary Direction ... + + // + // Check Price Change Rate ... + + // + bool isBullish = + // + hhDiff <= 1 && + llIDX > hhIDX && + priceChangePercent > 0 && + priceChangePercent >= minPriceChangePercent && + currVelocity > (velocitiesAvg * rangeExtendMultiplier) + // + ; + + // + bool isBearish = + // + llDiff <= 1 && + hhIDX > llIDX && + priceChangePercent < 0 && + MathAbs(priceChangePercent) >= minPriceChangePercent && + currVelocity > (velocitiesAvg * rangeExtendMultiplier) + // + ; + + // + result = isBullish || + isBearish; + if (result) + { + // + rootIDX = + isBullish + ? llIDX + : hhIDX; + + // + dir = isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + return result; + } + + // + // Actions ... + + /** + * Check a Bar is End of an OrderBlock Bar or Not ... + * + * @param bar: XOHCL ... + * @param box: XBoxZone ... + * @param forceFVGBarType: bool, Force all Bars must be Same as Direction ... + * @param forceOBTwoBar: bool, Force Two Bars of OB Start must be InDirection ... + * + * @return ( bool ) + */ + bool IsOB( + XOHCL &bar, + XBoxZone &box, + bool forceFVGBarType = false, + bool forceOBTwoBar = false // + ) + { + // + bool result = false; + + // + box.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Check Bar Must be FVG ... + result = IsFVG( + bar, + box, + forceFVGBarType // + ); + if (!result) + { + // + box.Clean(); + + // + return result; + } + + // + box.type = "XOB"; + + // + bool isBullish = box.IsBullish(); + bool isBearish = box.IsBearish(); + + // + // Order Block Includes an FVG which Starts by atleast One + // or More Indirectional Bars ... + XOHCL fvgLastBar; + XOHCL fvgLastBarPrev; + XOHCL fvgLastBarPrev2; + + // + int barIndex = bar.Index(); + int fvgLastBarIndex = barIndex + 3; + result = fvgLastBar.Init( + bar.symbol, + bar.period, + fvgLastBarIndex // + ); + result = + result && + fvgLastBar.GetPreviousBar(fvgLastBarPrev); + result = + result && + fvgLastBarPrev.GetPreviousBar(fvgLastBarPrev2); + if (!result) + { + // + box.Clean(); + fvgLastBar.Clean(); + fvgLastBarPrev.Clean(); + fvgLastBarPrev2.Clean(); + + // + return result; + } + + // + // Check FVG Last Bar ... + + // + bool isBullishBlock = + isBullish && + (fvgLastBar.IsBearish() || + (fvgLastBar.IsBullish() && + fvgLastBarPrev.IsBearish())); + + // + bool isBearishBlock = + isBearish && + (fvgLastBar.IsBullish() || + (fvgLastBar.IsBearish() && + fvgLastBarPrev.IsBullish())); + + // + // Update Box ... + + // + if (isBullishBlock || + isBearishBlock) + { + // + box.from = fvgLastBar.time; + + // + box.lower = MathMin(box.lower, fvgLastBar.low); + box.upper = MathMax(box.upper, fvgLastBar.high); + } + + // + // Apply Force Two Bar ... + if (forceOBTwoBar) + { + // + isBullishBlock = + isBullishBlock && + fvgLastBarPrev.IsBearish(); + + // + isBearishBlock = + isBearishBlock && + fvgLastBarPrev.IsBullish(); + + // + // Update Box ... + if (isBullishBlock || + isBearishBlock) + { + // + box.from = fvgLastBarPrev.time; + box.lower = MathMin(box.lower, fvgLastBarPrev.low); + box.upper = MathMax(box.upper, fvgLastBarPrev.high); + } + } + + // + result = isBullishBlock || + isBearishBlock; + if (!result) + { + // + box.Clean(); + fvgLastBar.Clean(); + fvgLastBarPrev.Clean(); + + // + return result; + } + + // + result = box.IsValid(); + + // + // Cleanup Resources ... + + // + fvgLastBar.Clean(); + fvgLastBarPrev.Clean(); + + // + return result; + } + + /** + * Check a Bar is End of an FVG Bar or Not ... + * + * @param bar: XOHCL ... + * @param box: XBoxZone ... + * @param forceType: bool, Force all Bars must be Same as Direction ... + * + * @return ( bool ) + */ + bool IsFVG( + XOHCL &bar, + XBoxZone &box, + bool forceType = false // + ) + { + // + bool result = false; + + // + box.Clean(); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL pBar; + XOHCL p2Bar; + result = bar.GetPreviousBar(pBar); + result = result && + pBar.GetPreviousBar(p2Bar); + if (!result) + { + // + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + bool isBullish = p2Bar.high < bar.low; + bool isBearish = p2Bar.low > bar.high; + + // + result = isBullish || + isBearish; + + // + // Apply Force Type ... + if (result) + { + // + if (isBullish) + { + // + result = + bar.IsBullish() && + pBar.IsBullish() && + p2Bar.IsBullish(); + } + else if (isBearish) + { + // + result = + bar.IsBearish() && + pBar.IsBearish() && + p2Bar.IsBearish(); + } + } + + // + if (result) + { + // + box.to = bar.time; + box.from = p2Bar.time; + box.symbol = bar.symbol; + box.period = bar.period; + box.dir = isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + box.upper = isBullish + ? bar.low + : p2Bar.low; + box.lower = isBullish + ? p2Bar.high + : bar.high; + box.type = "XFVG"; + } + + // + pBar.Clean(); + p2Bar.Clean(); + + // + result = box.IsValid(); + + // + return result; + } + + /** + * Check a Bar is a Trigger Box or Not ... + * + * @param bar: XOHCL instance Referernce, Specified Start Bar to Check ... + * @param trigger: XBoxZone instance Reference, Holds Detected Trigger Bar ... + * @param ob: XBoxZone instance Reference, Holds Detected Trigger Bar's OB ... + * @param fvg: XBoxZone instance Reference, Holds Detected Trigger Bar's FVG ... + * @param rLiquidity: XBoxZone instance Reference, Holds Detected Trigger Bar's Reversal Side Liquidity ... + * @param fLiquidity: XBoxZone instance Reference, Holds Detected Trigger Bar's Following Side Liquidity ... + * @param swingBar: XOHCL instance Referernce, Holds Detected Trigger Bar's Swing ... + * @param loopback: int, Loopback Bars Count ... + * @param maxAllowedRange: double, Max Allowed Trigger's OB Range ... + * @param minAllowedBlockEdgeLength: int, Min Allowed Block Edge Validation Length ... + * @param forceOBOppositBar: bool, Force OB to Start by Opposite Bar ... + * @param forceFVGBarType: bool, Force FVG to Has Same Bar Type ... + * @param forceGapBarBreakout: bool, Force Gap Bar Breakout OB Edge ... + * @param forceHasSwingBar: bool, Force Has Swing Bar ... + * @param forceHasLiquidity: bool, Force Has Following Liquidity ... + * @param forceHasReversalLiquidity: bool, Force Has Reversal Liquidity ... + * + * @return ( bool ) + */ + bool IsTrigger( + XOHCL &bar, + XBoxZone &trigger, + XBoxZone &ob, + XBoxZone &fvg, + XBoxZone &rLiquidity, + XBoxZone &fLiquidity, + XOHCL &swingBar, + int loopback = 10, + double maxAllowedRange = 0.0, + int minAllowedBlockEdgeLength = 0, + bool forceOBOppositBar = true, + bool forceFVGBarType = true, + bool forceGapBarBreakout = true, + bool forceHasSwingBar = true, + bool forceHasLiquidity = true, + bool forceHasReversalLiquidity = true // + ) + { + // + bool result = false; + + // + // Normalize Args ... + ob.Clean(); + fvg.Clean(); + trigger.Clean(); + swingBar.Clean(); + rLiquidity.Clean(); + fLiquidity.Clean(); + loopback = NormalizeInt(loopback, 5); + + // + // Validate Args ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL pBar; + XOHCL tmpBar; + XOHCL tmpPBar; + ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; + + // + result = bar.GetPreviousBar(pBar); + + // + // Detect Base Order Block ... + result = + result && + // + // Order Block Detection ... + IsOB( + pBar, + ob, + forceFVGBarType, + forceOBOppositBar // + ) && + // + // Gap Detection ... + IsFVG( + pBar, + fvg, + forceFVGBarType // + ); + if (result) + { + // + trigger = ob; + trigger.type = "XTRG"; + } + + // + // Reading Requirements ... + + // + double points = GetPoints(bar.symbol); + + // + bool isBullish = ob.IsBullish(); + bool isBearish = ob.IsBearish(); + + // + int toIDX = trigger.ToIndex(); + int fromIDX = trigger.FromIndex(); + + // + // Validate Gaps Bar Breakeout ... + if (result && + forceGapBarBreakout) + { + // + // Extract Gap Bar ... + tmpBar.Clean(); + tmpPBar.Clean(); + result = + // + // Retrieve Bars ... + fvg.ToBar(tmpBar) && + tmpBar.GetPreviousBar(tmpPBar) && + // + // Validate Gap Bar is Momentum Bar ... + IsMomentum( + tmpPBar, + iDir, + 1 // + ) && + iDir == fvg.dir && + // + // Validate ... + (isBullish + ? tmpPBar.close > ob.upper + : tmpPBar.close < ob.lower); + + // + tmpBar.Clean(); + tmpPBar.Clean(); + } + + // + // Validate Range ... + if (result && + maxAllowedRange > 0) + { + // + double range = ob.GetRange(); + result = range <= (maxAllowedRange * points); + } + + // + // Validating Swing Bar ... + if (result && + forceHasSwingBar) + { + // + int swingIDX = -1; + result = ob.FromBar(tmpBar); + if (result) + { + // + // Detect Swing Bar Index ... + if (isBullish) + { + swingIDX = tmpBar.FindLowestIndex(loopback, MODE_LOW); + } + else if (isBearish) + { + swingIDX = tmpBar.FindHighestIndex(loopback, MODE_HIGH); + } + result = IsValidIndex(swingIDX); + if (result) + { + // + // Initialize Swing Bar ... + result = swingBar.Init( + bar.symbol, + bar.period, + swingIDX // + ); + } + + // + // Update Trigger Block based on Swing Bar ... + result = swingBar.IsValid(); + if (result) + { + // + // Update From ... + trigger.from = ((datetime)MathMin((int)trigger.from, (int)swingBar.time)); + + // + // Update Edge ... + if (isBullish) + { + trigger.lower = MathMin(trigger.lower, swingBar.GetDown()); + } + else if (isBearish) + { + trigger.upper = MathMax(trigger.upper, swingBar.GetUp()); + } + } + } + + // + tmpBar.Clean(); + } + + // + // Validate Min Block Edge ... + if (result && + minAllowedBlockEdgeLength > 0) + { + // + fromIDX = trigger.FromIndex(); + if (result) + { + // + // Looping Back ... + for (int i = fromIDX; i < fromIDX + minAllowedBlockEdgeLength; i++) + { + // + // Initialize i Bar ... + result = tmpBar.Init( + bar.symbol, + bar.period, + i // + ); + result = + result && + (isBullish + ? tmpBar.low > trigger.lower + : tmpBar.high > trigger.upper); + if (!result) + { + break; + } + + // + tmpBar.Clean(); + } + result = tmpBar.IsValid(); + + // + // Update Trigger Block ... + if (result) + { + trigger.from = ((datetime)(MathMin((int)trigger.from, (int)tmpBar.time))); + } + } + + // + tmpBar.Clean(); + } + + // + // Validating Liquidity ... + if (result && + (forceHasLiquidity || + forceHasReversalLiquidity)) + { + // + // Try to Detect Liquidity ... + toIDX = ob.ToIndex(); + for (int i = toIDX; i < toIDX + (loopback * 10); i++) + { + // + // Initialize i Bar ... + result = tmpBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!result) + { + break; + } + + // + // Detect Liquidity ... + bool isRejected = + result && + IsRejected( + tmpBar, + iDir, + false, // Force Bar Type ... + true // Force Fibo Pressure ... + ); + bool isBullishRejected = + isRejected && + IsBullish(iDir); + bool isBearishRejected = + isRejected && + IsBearish(iDir); + + // + // Validate Liquidities ... + if (isBullish) + { + // + if (isBullishRejected && + forceHasLiquidity && + !fLiquidity.IsValid() && + tmpBar.low < trigger.lower) + { + // + // Filling Following Liquidity ... + FillLiquidity( + tmpBar, + trigger.dir, + fLiquidity, + trigger.to // + ); + } + + // + if (isBearishRejected && + !rLiquidity.IsValid() && + forceHasReversalLiquidity && + tmpBar.high > trigger.upper) + { + // + // Filling Revrsal Liquidity ... + FillLiquidity( + tmpBar, + Opposit(trigger.dir), + rLiquidity, + trigger.to // + ); + } + } + else if (isBearish) + { + // + if (isBearishRejected && + forceHasLiquidity && + !fLiquidity.IsValid() && + tmpBar.high > trigger.upper) + { + // + // Filling Following Liquidity ... + FillLiquidity( + tmpBar, + trigger.dir, + fLiquidity, + trigger.to // + ); + } + + // + if (isBullishRejected && + !rLiquidity.IsValid() && + forceHasReversalLiquidity && + tmpBar.low < trigger.lower) + { + // + // Filling Reversal Liquidity ... + FillLiquidity( + tmpBar, + Opposit(trigger.dir), + rLiquidity, + trigger.to // + ); + } + } + + // + if ((!forceHasLiquidity + ? true + : fLiquidity.IsValid()) && + (!forceHasReversalLiquidity + ? true + : rLiquidity.IsValid())) + { + break; + } + + // + tmpBar.Clean(); + } + tmpBar.Clean(); + + // + result = (!forceHasLiquidity + ? true + : fLiquidity.IsValid()) && + (!forceHasReversalLiquidity + ? true + : rLiquidity.IsValid()); + } + + // + // Cleanup Resources ... + + // + pBar.Clean(); + tmpBar.Clean(); + tmpPBar.Clean(); + + // + if (!result) + { + // + ob.Clean(); + fvg.Clean(); + trigger.Clean(); + swingBar.Clean(); + rLiquidity.Clean(); + fLiquidity.Clean(); + + // + return result; + } + + // + return result; + } + + // + // Candlestick ... + + /** + * Check Specified Bar is Doji Pattern or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * @param shadowMultiplier: double, Specified Shadow Multiplier ... + * + * @return ( bool ) + */ + bool IsDoji( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + double shadowMultiplier = 1.5 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + shadowMultiplier = NormalizeDouble(shadowMultiplier, 1.5, 3); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double body = bar.GetBody(); + double range = bar.GetRange(); + + // + result = + body > 0 && + range > 0 + ? (body / range < 0.1) + : false; + if (result) + { + // + dir = + bar.GetLowShadow() >= (bar.GetHighShadow() * shadowMultiplier) + ? X_DIRECTION_BULLISH + : bar.GetHighShadow() >= (bar.GetLowShadow() * shadowMultiplier) + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + // + result = HasDirection(dir); + } + + // + return result; + } + + /** + * Check Specified Bar is Swing or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * @param loopback: int, Specified Loopback ... + * + * @return ( bool ) + */ + bool IsSwing( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int loopback = 7 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + loopback = NormalizeInt(loopback, 1); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + XOHCL ppBar; + result = pBar.GetPreviousBar(ppBar); + if (!result) + { + // + pBar.Clean(); + ppBar.Clean(); + return result; + } + + // + bool isBullish = + // + pBar.low < bar.low && + pBar.low < ppBar.low && + bar.GetDown() > pBar.low + // + ; + + // + bool isBearish = + // + pBar.high > bar.high && + pBar.high > ppBar.high && + bar.GetUp() < pBar.high + // + ; + + // + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + ppBar.Clean(); + int pBarIDX = pBar.Index(); + for (int i = pBarIDX + 1; i < pBarIDX + loopback; i++) + { + // + bool has = ppBar.Init( + pBar.symbol, + pBar.period, + i // + ); + + // + isBullish = + has && + isBullish && + pBar.low < ppBar.low; + + // + isBearish = + has && + isBearish && + pBar.high > ppBar.high; + } + + // + result = isBullish || + isBearish; + if (!result) + { + dir = X_DIRECTION_NONE; + } + } + + // + // Cleanup Resources ... + + // + pBar.Clean(); + ppBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar's Prev Bar is Simple Swing or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to it's Prev Check ... + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * + * @return ( bool ) + */ + bool IsSimpleSwing( + XOHCL &bar, + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + // Valdate Args ... + result = bar.IsValid(); + + // + // Reading Requirements ... + XOHCL cBar; + XOHCL pBar; + XOHCL p2Bar; + result = + bar.GetPreviousBar(cBar); + result = + result && + cBar.GetPreviousBar(pBar); + result = + result && + pBar.GetPreviousBar(p2Bar); + if (!result) + { + // + cBar.Clean(); + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + // Now we Have to Check pBar is Swing Low or High ... + + // + bool isPBarSwingLow = + pBar.low < cBar.low && + pBar.low < p2Bar.low; + + // + bool isPBarSwingHigh = + pBar.high > cBar.high && + pBar.high > p2Bar.high; + + // + result = isPBarSwingLow || + isPBarSwingHigh; + if (result) + { + // + dir = isPBarSwingLow + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + // Cleanup Resourses ... + + // + cBar.Clean(); + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar is Hammer Pattern or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * @param bodyMultiplier: double, Specified Body Multiplier ... + * + * @return ( bool ) + */ + bool IsHammer( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + double bodyMultiplier = 2.0 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + bodyMultiplier = NormalizeDouble(bodyMultiplier, 1.5, 3); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + double body = bar.GetBody(); + double lShadow = bar.GetLowShadow(); + double hShadow = bar.GetHighShadow(); + + // + bool isBullish = + hShadow < body && + lShadow > (bodyMultiplier * body); + + // + bool isBearish = + lShadow < body && + hShadow > (bodyMultiplier * body); + + // + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + return result; + } + + /** + * Check Specified Bar is Engulfed Prev Bar or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * + * @return ( bool ) + */ + bool IsEngulfed( + XOHCL &bar, + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + result = bar.GetBody() > pBar.GetBody(); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + bool isBullish = + bar.IsBullish() && + pBar.IsBearish() && + bar.GetDown() <= pBar.GetDown() && + bar.GetUp() > pBar.GetUp(); + + // + bool isBearish = + bar.IsBearish() && + pBar.IsBullish() && + bar.GetUp() >= pBar.GetUp() && + bar.GetDown() < pBar.GetDown(); + + // + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + // Cleanup Resources ... + + // + pBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar is Momentum Bar or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * @param forceBarType: bool, Force Apply Bar Type ... + * @param forceFiboPressure: bool, Force Apply Bar Type ... + * + * @return ( bool ) + */ + bool IsRejected( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + bool forceBarType = true, + bool forceFiboPressure = true // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + bool isBullish = + // + bar.low < pBar.low && + bar.GetShadows() > bar.GetBody() && + bar.GetLowShadow() > bar.GetBody() && + bar.GetLowShadow() > bar.GetHighShadow() + // + ; + + // + bool isBearish = + // + bar.high > pBar.high && + bar.GetShadows() > bar.GetBody() && + bar.GetHighShadow() > bar.GetBody() && + bar.GetHighShadow() > bar.GetLowShadow() + // + ; + + // + result = isBullish || + isBearish; + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + // Check Force Type ... + if (forceBarType) + { + // + isBullish = + isBullish && + bar.IsBullish(); + + // + isBearish = + isBearish && + bar.IsBearish(); + + // + result = isBullish || + isBearish; + if (!result) + { + // + pBar.Clean(); + return result; + } + } + + // + // Check Force Fibo Pressure ... + if (forceFiboPressure) + { + // + bool hasBullishFiboPressure = + HasFiboPressure( + bar, + X_DIRECTION_BULLISH, + X_FIBO_LEVEL_236 // + ); + + // + bool hasBearishFiboPressure = + HasFiboPressure( + bar, + X_DIRECTION_BEARISH, + X_FIBO_LEVEL_236 // + ); + + // + isBullish = + isBullish && + hasBullishFiboPressure; + + // + isBearish = + isBearish && + hasBearishFiboPressure; + } + + // + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + pBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar is Momentum Bar or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * @param loopback: int, Specified Loopback ... + * + * @return ( bool ) + */ + bool IsMomentum( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int loopback = 2 // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + loopback = NormalizeInt(loopback, 1); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + // Calculate HH and LL ... + double hh = 0; + double ll = 0; + int hhIDX = -1; + int llIDX = -1; + result = CalculateLoopbackHLData( + hhIDX, + hh, + llIDX, + ll, + bar, + loopback // s + ); + result = + result && + ll > 0 && + hh > ll && + IsValidIndex(llIDX) && + IsValidIndex(hhIDX); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + bool isBullish = + bar.low > ll && + bar.close >= hh && + bar.IsBullish() && + bar.low > pBar.low && + bar.high > pBar.high && + bar.GetBody() > pBar.GetBody() && + bar.GetRange() > pBar.GetRange() && + bar.GetShadows() < pBar.GetShadows(); + + // + bool isBearish = + bar.high < hh && + bar.close <= ll && + bar.IsBearish() && + bar.low < pBar.low && + bar.high < pBar.high && + bar.GetBody() > pBar.GetBody() && + bar.GetRange() > pBar.GetRange() && + bar.GetShadows() < pBar.GetShadows(); + + // + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + pBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar is Pullback or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Specified Direction ... + * @param loopback: int, Specified Loopback ... + * @param forceBody: bool, Force Using Body ... + * + * @return ( bool ) + */ + bool IsPullback( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int loopback = 3, + bool forceBody = false // + ) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + loopback = NormalizeInt(loopback, 3); + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Check Bar Must Engulfed ... + result = IsEngulfed( + bar, + dir // + ); + if (!result) + { + return result; + } + + // + // Calculate HH and LL ... + double hh = 0; + double ll = 0; + int hhIDX = -1; + int llIDX = -1; + result = CalculateLoopbackHLData( + hhIDX, + hh, + llIDX, + ll, + bar, + loopback // + ); + result = + result && + ll > 0 && + hh > ll && + IsValidIndex(llIDX) && + IsValidIndex(hhIDX); + if (!result) + { + return result; + } + + // + bool isBullish = + bar.high > hh && + bar.low > ll; + + // + bool isBearish = + bar.high < hh && + bar.low < ll; + + // + result = isBullish || + isBearish; + if (result) + { + // + if (forceBody) + { + // + isBullish = + isBullish && + bar.GetUp() > hh && + bar.GetDown() > ll && + llIDX == bar.Index() + 1; + + // + isBearish = + isBearish && + bar.GetUp() < hh && + bar.GetDown() < ll && + hhIDX == bar.Index() + 1; + + // + result = isBullish || + isBearish; + } + + // + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + } + + // + return result; + } + + /** + * Check Specified Bar is Sequence Edge Breaker Bar or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Holds Founded Direction ... + * @param loopback: int, Specified Loopback ... + * + * @return ( bool ) + */ + bool IsSeqBreakEdge( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int loopback = 3 // + ) + { + // + bool result = false; + + // + // Normalize Args ... + dir = X_DIRECTION_NONE; + loopback = NormalizeInt(loopback, 3); + + // + // Validate Args ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + bool isBullish = false; + bool isBearish = false; + + // + // Check Has Sequence or not ... + XOHCL pBar; + XOHCL iBar; + XOHCL iPBar; + bool has = false; + int index = bar.Index(); + int start = index + 1; + int end = start + loopback - 1; + bool hasBullishSeq = true; + bool hasBearishSeq = true; + for (int i = start; i < end; i++) + { + // + // Initialize Indexed Bar(s) ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + has = + has && + iBar.GetPreviousBar(iPBar); + + // + // Bullish Sequence ... + if (hasBullishSeq) + { + // + hasBullishSeq = + has && + iBar.low > iPBar.low; + } + + // + // Bearish Sequence ... + if (hasBearishSeq) + { + // + hasBearishSeq = + has && + iBar.high < iPBar.high; + } + + // + if (!hasBullishSeq && + !hasBearishSeq) + { + break; + } + + // + iBar.Clean(); + iPBar.Clean(); + } + iBar.Clean(); + iPBar.Clean(); + + // + // Check a Sequence Detect ... + result = hasBullishSeq || + hasBearishSeq; + if (!result) + { + // + pBar.Clean(); + iBar.Clean(); + iPBar.Clean(); + + // + return result; + } + + // + // Retrieve Previous Bar ... + result = bar.GetPreviousBar(pBar); + + // + // Now we Have Ensure has a Sequence ... + + // + isBullish = + result && + hasBearishSeq && + bar.high > pBar.high; + + // + isBearish = + result && + hasBullishSeq && + bar.low < pBar.low; + + // + // Summarizing Result ... + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + // Cleanup Resources ... + pBar.Clean(); + iBar.Clean(); + iPBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar is Sequence Type Breaker Bar or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Holds Founded Direction ... + * @param loopback: int, Specified Loopback ... + * + * @return ( bool ) + */ + bool IsSeqBreakType( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int loopback = 3 // + ) + { + // + bool result = false; + + // + // Normalize Args ... + dir = X_DIRECTION_NONE; + loopback = NormalizeInt(loopback, 3); + + // + // Validate Args ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + bool isBullish = false; + bool isBearish = false; + + // + // Check Has Sequence or not ... + XOHCL iBar; + bool has = false; + int index = bar.Index(); + int start = index + 1; + int end = start + loopback; + bool hasBullishSeq = true; + bool hasBearishSeq = true; + for (int i = start; i < end; i++) + { + // + // Initialize Indexed Bar(s) ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + + // + // Bullish Sequence ... + if (hasBullishSeq) + { + // + hasBullishSeq = + has && + iBar.IsBullish(); + } + + // + // Bearish Sequence ... + if (hasBearishSeq) + { + // + hasBearishSeq = + has && + iBar.IsBearish(); + } + + // + if (!hasBullishSeq && + !hasBearishSeq) + { + break; + } + + // + iBar.Clean(); + } + iBar.Clean(); + + // + // Check a Sequence Detect ... + result = hasBullishSeq || + hasBearishSeq; + if (!result) + { + // + iBar.Clean(); + + // + return result; + } + + // + // Now we Have Ensure has a Sequence ... + + // + isBullish = + result && + hasBearishSeq && + bar.IsBullish(); + + // + isBearish = + result && + hasBullishSeq && + bar.IsBearish(); + + // + // Summarizing Result ... + result = isBullish || + isBearish; + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar is Fully Sequence Breker Bar or not ... + * + * @param bar: XOHCL instance reference, Specified Bar to Check ... + * @param dir: ENUM_X_DIRECTION member, Holds Founded Direction ... + * @param loopback: int, Specified Loopback ... + * + * @return ( bool ) + */ + bool IsSeqBreak( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int loopback = 3 // + ) + { + // + bool result = false; + + // + // Normalize Args ... + dir = X_DIRECTION_NONE; + loopback = NormalizeInt(loopback, 3); + + // + // Validate Args ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Check Seq Edge ... + ENUM_X_DIRECTION seqEdgeDir; + bool isSeqEdgeBreaked = IsSeqBreakEdge( + bar, + seqEdgeDir // + ); + + // + // Check Seq Type ... + ENUM_X_DIRECTION seqTypeDir; + bool isSeqTypeBreaked = IsSeqBreakType( + bar, + seqTypeDir // + ); + + // + // Check Result ... + result = isSeqEdgeBreaked && + isSeqTypeBreaked && + seqEdgeDir == seqTypeDir; + if (result) + { + dir = seqEdgeDir; + } + + // + return result; + } + + // + // + // + + /** + * Check a Bar is Valid for Specified Direction of Positions ... + * + * @param bar: XOHCL instance, Start Bar ... + * @param dir: ENUM_X_DIRECTION member, Provide Direction ... + * + * @return ( bool ) + */ + bool IsValidForTrigger( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + bool allowCond1 = true, + bool allowCond2 = true, + bool allowCond3 = true, + bool allowCond4 = true, + bool allowCond5 = true, + bool allowCond6 = true, + bool allowCond7 = true // + ) + { + // + bool result = false; + + // + // Normalize Args ... + dir = X_DIRECTION_NONE; + + // + // Validate Args ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Prepare Requirements ... + XOHCL pBar; + XOHCL p2Bar; + int loopback = 3; + bool isBullish = false; + bool isBearish = false; + ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; + + // + // Retrieve Bar's Prev ... + result = bar.GetPreviousBar(pBar); + result = result && + pBar.GetPreviousBar(p2Bar); + + // + // Handle Detect Trigger Bar ... + if (result) + { + // + // Check States ... + + // + // Rejected ... + bool isRejected = IsRejected( + pBar, + iDir, + false, // Force Type ... + true // Force Fibo Pressure ... + ); + bool isBullishRejected = + isRejected && + IsBullish(iDir); + bool isBearishRejected = + isRejected && + IsBearish(iDir); + + // + // Simple Rejected ... + bool isSimpleRejected = IsRejected( + pBar, + iDir, + false, // Force Type ... + false // Force Fibo Pressure ... + ); + bool isSimpleBullishRejected = + isSimpleRejected && + IsBullish(iDir); + bool isSimpleBearishRejected = + isSimpleRejected && + IsBearish(iDir); + + // + // Full Directional Rejection ... + bool isFullRejected = IsRejected( + pBar, + iDir, + true, // Force Type ... + true // Force Fibo Pressure ... + ); + bool isFullBullishRejected = + isFullRejected && + IsBullish(iDir); + bool isFullBearishRejected = + isRejected && + IsBearish(iDir); + + // + // Engulfed ... + bool isEngulfed = IsEngulfed( + pBar, + iDir // + ); + bool isBullishEngulfed = + isEngulfed && + IsBullish(iDir); + bool isBearishEngulfed = + isEngulfed && + IsBearish(iDir); + + // + // Momentum ... + bool isMomentum = IsMomentum( + pBar, + iDir // + ); + bool isBullishMomentum = + isMomentum && + IsBullish(iDir); + bool isBearishMomentum = + isMomentum && + IsBearish(iDir); + + // + // Simple Swing ... + bool isSwing = IsSimpleSwing( + pBar, + iDir // + ); + bool isBullishSwing = + isSwing && + IsBullish(iDir); + bool isBearishSwing = + isSwing && + IsBearish(iDir); + + // + // Full Swing ... + bool isFullSwing = IsSwing( + pBar, + iDir, + 5 // + ); + bool isFullBullishSwing = + isFullSwing && + IsBullish(iDir); + bool isFullBearishSwing = + isFullSwing && + IsBearish(iDir); + + // + // Sequence Breaker ... + bool isSeqBreak = IsSeqBreak( + pBar, + iDir, + 3 // + ); + bool isBullishSeqBreak = + isSeqBreak && + IsBullish(iDir); + bool isBearishSeqBreak = + isSeqBreak && + IsBearish(iDir); + + // + // Now we have to Combine Conditions ... + + // + // Cond 1 ... + bool isBullishCond1 = false; + bool isBearishCond1 = false; + if (allowCond1) + { + // + // Bullish ... + isBullishCond1 = + // + isFullBullishRejected + // + ; + + // + // Bearish ... + isBearishCond1 = + // + isFullBearishRejected + // + ; + } + + // + // Cond 2 ... + bool isBullishCond2 = false; + bool isBearishCond2 = false; + if (allowCond2) + { + // + // Bullish ... + isBullishCond2 = + // + isBullishSwing && + isBullishRejected + // + ; + + // + // Bearish ... + isBearishCond2 = + // + isBearishSwing && + isBearishRejected + // + ; + } + + // + // Cond 3 ... + bool isBullishCond3 = false; + bool isBearishCond3 = false; + if (allowCond3) + { + // + // Bullish ... + isBullishCond3 = + // + isBullishSwing && + (isBullishRejected || + isBullishEngulfed || + isBullishMomentum) + // + ; + + // + // Bearish ... + isBearishCond3 = + // + isBearishSwing && + (isBearishRejected || + isBearishEngulfed || + isBearishMomentum) + // + ; + } + + // + // Cond 4 ... + bool isBullishCond4 = false; + bool isBearishCond4 = false; + if (allowCond4) + { + // + // Bullish ... + isBullishCond4 = + // + isBullishSwing && + isBullishSeqBreak && + (isBullishRejected || + isBullishEngulfed || + isBullishMomentum) + // + ; + + // + // Bearish ... + isBearishCond4 = + // + isBearishSwing && + isBearishSeqBreak && + (isBearishRejected || + isBearishEngulfed || + isBearishMomentum) + // + ; + } + + // + // Cond 5 ... + bool isBullishCond5 = false; + bool isBearishCond5 = false; + if (allowCond5) + { + // + // Bullish ... + isBullishCond5 = + // + isFullBullishSwing && + (isBullishRejected || + isBullishEngulfed || + isBullishMomentum) + // + ; + + // + // Bearish ... + isBearishCond5 = + // + isFullBearishSwing && + (isBearishRejected || + isBearishEngulfed || + isBearishMomentum) + // + ; + } + + // + // Cond 6 ... + bool isBullishCond6 = false; + bool isBearishCond6 = false; + if (allowCond6) + { + // + // Bullish ... + isBullishCond6 = + // + p2Bar.IsBearish() && + pBar.IsBullish() && + pBar.low < p2Bar.low && + pBar.high > p2Bar.high && + pBar.GetDown() <= p2Bar.GetDown() && + (isBullishEngulfed || + isBullishMomentum || + isSimpleBullishRejected) + // + ; + + // + // Bearish ... + isBearishCond6 = + // + p2Bar.IsBullish() && + pBar.IsBearish() && + pBar.high > p2Bar.high && + pBar.low < p2Bar.low && + pBar.GetUp() >= p2Bar.GetUp() && + (isBearishEngulfed || + isBearishMomentum || + isSimpleBearishRejected) + // + ; + } + + // + // Cond 7 ... + bool isBullishCond7 = false; + bool isBearishCond7 = false; + if (allowCond7) + { + // + // Bullish ... + isBullishCond7 = + // + p2Bar.IsBearish() && + pBar.IsBullish() && + pBar.low < p2Bar.low && + pBar.high > p2Bar.high && + pBar.GetUp() >= p2Bar.GetUp() + // + ; + + // + // Bearish ... + isBearishCond7 = + // + p2Bar.IsBullish() && + pBar.IsBearish() && + pBar.high > p2Bar.high && + pBar.low < p2Bar.low && + pBar.GetDown() <= p2Bar.GetDown() + // + ; + } + + // + // Summarizie Result ... + + // + isBullish = + // + isBullishCond1 || + isBullishCond2 || + isBullishCond3 || + isBullishCond4 || + isBullishCond5 || + isBullishCond6 || + isBullishCond7 + // + ; + + // + isBearish = + // + isBearishCond1 || + isBearishCond2 || + isBearishCond3 || + isBearishCond4 || + isBearishCond5 || + isBearishCond6 || + isBearishCond7 + // + ; + } + + // + // Summarize Result ... + result = (isBullish && + !isBearish) || + (isBearish && + !isBullish); + if (result) + { + // + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + // Cleanup Resources ... + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + protected: + // + + // + private: + // + + // + // Props ... + + // + // Actions ... + + // +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-chart.helper.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCChartHelper +// Description: Chart Helper Tools ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" + +// +// Implementation ... +class XCChartHelper : public XCBase +{ + // + // Public ... + public: + // + + // + // Constructor ... + XCChartHelper( + ulong _chartId = 0, + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL) + { + // + bool canSetSymbolPeriod = + IsSpecifiedValid(_symbol) && + IsSpecifiedValid(_period); + + // + // Normalize ... + if (!canSetSymbolPeriod) + { + // + mChartID = NormalizeChartId(_chartId); + mSymbol = NormalizeSymbol(_symbol); + mPeriod = NormalizePeriod(_period); + } + else + { + // + SetSymbolPeriod(mSymbol, mPeriod); + } + } + + // + // Desconstructor ... + ~XCChartHelper() + { + } + + // + // Actioins ... + + /** + * Redraw Specified Chart ... + */ + void Redraw() + { + ChartRedraw(mChartID); + } + + /** + * Chart Navigation ... + * + * @param position: ENUM_CHART_POSITION + * @param shift: int + * + * @return ( bool ) + */ + bool Navigate( + ENUM_CHART_POSITION position, + int shift // + ) + { + return (ChartNavigate(mChartID, position, shift)); + } + + /** + * Apply a Template to Chart ... + * + * @param filename: string file path ... + * + * @return ( bool ) + */ + bool ApplyTemplate(string filename) + { + return (ChartApplyTemplate(mChartID, filename)); + } + + /** + * Add Specified Indicator to Chart ... + * + * @param subWindow: int ... + * @param handle: int ... + * + * @return ( bool ) + */ + bool IndicatorAdd(int subWindow, int handle) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartIndicatorAdd(mChartID, subWindow, handle)); + } + + /** + * Delete Specified Indicator from Chart ... + * + * @param subWindow: int ... + * @param name: string ... + * + * @return ( bool ) + */ + bool IndicatorDelete(int subWindow, string name) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartIndicatorDelete(mChartID, subWindow, name)); + } + + /** + * Count all Charts Indicator ... + * + * @param subWindow: int ... + * + * @return ( int ) + */ + int IndicatorsTotal(int subWindow) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartIndicatorsTotal(mChartID, subWindow)); + } + + /** + * Get Specified Indexed Indicator's Name ... + * + * @param subWindow: int ... + * @param index: int ... + * + * @return ( string ) + */ + string IndicatorName(int subWindow, int index) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartIndicatorName(mChartID, subWindow, index)); + } + + /** + * Set Chart Symbol, Period ... + * + * @param symbol: string ... + * @param period: ENUM_TIMEFRAMES ... + * + * @return ( bool ) + */ + bool SetSymbolPeriod( + string symbol, + ENUM_TIMEFRAMES period // + ) + { + bool result = (ChartSetSymbolPeriod(mChartID, symbol, period)); + if (result) + { + // + mSymbol = symbol; + mPeriod = period; + } + + // + return result; + } + + /** + * Take an Screenshot of Chart ... + * + * @param filename: string file path ... + * @param width: int ... + * @param height: int ... + * @param align_mode: ENUM_ALIGN_MODE ... + * + * @return ( bool ) + */ + bool ScreenShot( + const string filename, + const int width, + const int height, + const ENUM_ALIGN_MODE align_mode // + ) const + { + return (ChartScreenShot(mChartID, filename, width, height, align_mode)); + } + + /** + * Writing parameters of chart to file ... + **/ + bool Save(const int file_handle) + { + // + string work_str; + int work_int; + + // + bool has = false; + + // + // Validate ... + if (file_handle == INVALID_HANDLE || mChartID == -1) + { + return has; + } + + // + // Write start marker - 0xFFFFFFFFFFFFFFFF ... + has = FileWriteLong(file_handle, -1) == sizeof(long); + if (!has) + { + return has; + } + + // + // Write chart type ... + has = FileWriteInteger(file_handle, Type(), INT_VALUE) == INT_VALUE; + if (!has) + { + return has; + } + + // + // Write chart symbol ... + work_str = Symbol(); + work_int = StringLen(work_str); + has = FileWriteInteger(file_handle, work_int, INT_VALUE) == INT_VALUE; + if (!has) + { + return has; + } + if (work_int != 0) + { + // + has = FileWriteString(file_handle, work_str, work_int) == work_int; + if (!has) + { + return has; + } + } + + // + // Write Period of chart ... + has = FileWriteInteger(file_handle, Period(), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "Mode" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_MODE), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "Foreground" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_FOREGROUND), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "Shift" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHIFT), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShiftSize" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHIFT), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "AutoScroll" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_AUTOSCROLL), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "Scale" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALE), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "ScaleFix" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALEFIX), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ScaleFix_11" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALEFIX_11), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "FixedMax" property ... + has = FileWriteDouble(file_handle, ChartGetDouble(mChartID, CHART_FIXED_MAX)) == sizeof(double); + if (!has) + { + return has; + } + + // + // Write value of the "FixedMin" property ... + has = FileWriteDouble(file_handle, ChartGetDouble(mChartID, CHART_FIXED_MIN)) == sizeof(double); + if (!has) + { + return has; + } + + // + // Write the "ScalePPB" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SCALE_PT_PER_BAR), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "PointsPerBar" property ... + has = FileWriteDouble(file_handle, ChartGetDouble(mChartID, CHART_POINTS_PER_BAR)) == sizeof(double); + if (!has) + { + return has; + } + + // + // Write value of the "ShowOHLC" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_OHLC), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowLineBid" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_BID_LINE), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowLineAsk" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_ASK_LINE), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowLastLine" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_LAST_LINE), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowPeriodSep" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_PERIOD_SEP), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowGrid" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_GRID), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + // Write value of the "ShowVolumes" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_VOLUMES), INT_VALUE) == sizeof(int); + if (!has) + { + return has; + } + + // + // Write value of the "ShowObjectDescr" property ... + has = FileWriteInteger(file_handle, (int)ChartGetInteger(mChartID, CHART_SHOW_OBJECT_DESCR), CHAR_VALUE) == sizeof(char); + if (!has) + { + return has; + } + + // + return has; + } + + /** + * Load Specified Chart File ... + * + * @param file_handle: int ... + * + * @return ( bool ) + */ + bool Load(const int file_handle) + { + // + string work_str; + int work_int; + + // + bool has = false; + + // + // Validate ... + if (file_handle == INVALID_HANDLE || mChartID == -1) + { + return has; + } + + // + // Read and checking start marker - 0xFFFFFFFFFFFFFFFF ... + if (FileReadLong(file_handle) != -1) + return has; + + // + // Read and checking chart type ... + if (FileReadInteger(file_handle, INT_VALUE) != Type()) + return has; + + // + // Read chart symbol ... + work_int = FileReadInteger(file_handle); + if (work_int != 0) + { + work_str = FileReadString(file_handle, work_int); + } + else + { + work_str = ""; + } + + // + // Read chart period ... + work_int = FileReadInteger(file_handle); + SetSymbolPeriod(work_str, (ENUM_TIMEFRAMES)work_int); + + // + // Read value of the "Mode" property ... + has = ChartSetInteger(mChartID, CHART_MODE, FileReadInteger(file_handle, INT_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "Foreground" property ... + has = ChartSetInteger(mChartID, CHART_FOREGROUND, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "Shift" property ... + has = ChartSetInteger(mChartID, CHART_SHIFT, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "ShiftSize" property ... + has = ChartSetInteger(mChartID, CHART_SHIFT, FileReadInteger(file_handle, INT_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "AutoScroll" property ... + has = ChartSetInteger(mChartID, CHART_AUTOSCROLL, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "Scale" property ... + has = ChartSetInteger(mChartID, CHART_SCALE, FileReadInteger(file_handle, INT_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "ScaleFix" property ... + has = ChartSetInteger(mChartID, CHART_SCALEFIX, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Read value of the "ScaleFix_11" property ... + has = ChartSetInteger(mChartID, CHART_SCALEFIX_11, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "FixedMax" property ... + has = ChartSetDouble(mChartID, CHART_FIXED_MAX, FileReadDatetime(file_handle)); + if (!has) + { + return has; + } + + // + // Rread value of the "FixedMin" property ... + has = ChartSetDouble(mChartID, CHART_FIXED_MIN, FileReadDatetime(file_handle)); + if (!has) + { + return has; + } + + // + // Rread value of the "ScalePPB" property ... + has = ChartSetInteger(mChartID, CHART_SCALE_PT_PER_BAR, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "PointsPerBar" property ... + has = ChartSetDouble(mChartID, CHART_POINTS_PER_BAR, FileReadDatetime(file_handle)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowOHLC" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_OHLC, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowLineBid" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_BID_LINE, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowLineAsk" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_ASK_LINE, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowLastLine" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_LAST_LINE, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowPeriodSep" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_PERIOD_SEP, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowGrid" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_GRID, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowVolumes" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_VOLUMES, FileReadInteger(file_handle, INT_VALUE)); + if (!has) + { + return has; + } + + // + // Rread value of the "ShowObjectDescr" property ... + has = ChartSetInteger(mChartID, CHART_SHOW_OBJECT_DESCR, FileReadInteger(file_handle, CHAR_VALUE)); + if (!has) + { + return has; + } + + // + return has; + } + + ulong Open() + { + // + mChartID = ChartOpen(mSymbol, mPeriod); + return (mChartID); + } + + void Close() + { + // + if (mChartID != -1 && mChartID != 0) + { + ChartClose(mChartID); + mChartID = 0; + } + } + + // + // Properties ... + + /** + * Get Chart ID ... + * + * @return ( ulong ) + */ + ulong ChartId() + { + return mChartID; + } + + /** + * Get Object Type ... + * + * @return ( int ) + **/ + int Type() const + { + return (0x1111); + } + + /** + * Get Chart Mode ... + * + * @return ( ENUM_CHART_MODE ) + **/ + ENUM_CHART_MODE Mode() + { + return ((ENUM_CHART_MODE)ChartGetInteger(mChartID, CHART_MODE)); + } + + /** + * Get Chart Symbol ... + * + * @return ( string ) + */ + string Symbol() + { + return (ChartSymbol(mChartID)); + } + + /** + * Get Chart Period ... + * + * @return ( ENUM_TIMEFRAMES ) + */ + ENUM_TIMEFRAMES Period() + { + return (ChartPeriod(mChartID)); + } + + /** + * Count Chart Visible Bars ... + * + * @return ( int ) + */ + int VisibleBars() + { + return ((int)ChartGetInteger(mChartID, CHART_WIDTH_IN_BARS)); + } + + /** + * Get Chart First Visible Bars Index ... + * + * @return ( int ) + */ + int FirstVisibleBar() + { + return ((int)ChartGetInteger(mChartID, CHART_FIRST_VISIBLE_BAR)); + } + + /** + * Get Chart Last Visible Bars Index ... + * + * @return ( int ) + */ + int LastVisibleBar() + { + // + int first = FirstVisibleBar(); + int count = VisibleBars(); + int result = first + count; + return result; + } + + /** + * Get Chart's Specified SubWindows Minimum Price ... + * + * @param subWindow: int + * @return ( double ) + */ + double PriceMin(int subWindow = 0) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartGetDouble(mChartID, CHART_PRICE_MIN, subWindow)); + } + + /** + * Get Chart's Specified SubWindows Maximum Price ... + * + * @param subWindow: int + * @return ( double ) + */ + double PriceMax(int subWindow = 0) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (ChartGetDouble(mChartID, CHART_PRICE_MAX, subWindow)); + } + + /** + * Get Chart Width in Pixel ... + * + * @param subWindow: int ... + * + * @return ( int ) + */ + int Width(int subWindow = 0) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (int)ChartGetInteger(mChartID, CHART_WIDTH_IN_PIXELS, subWindow); + } + + /** + * Get Chart Height in Pixel ... + * + * @param subWindow: int ... + * + * @return ( int ) + */ + int Height(int subWindow = 0) + { + // + // Normalize Subwindow ... + if (subWindow <= 0) + { + subWindow = 0; + } + + // + return (int)ChartGetInteger(mChartID, CHART_HEIGHT_IN_PIXELS, subWindow); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + + // + ulong mChartID; // Chart ID ... + string mSymbol; // Chart Symbol ... + ENUM_TIMEFRAMES mPeriod; // Chart Period ... +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-cobject.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XChartObjects +// Description: provides all require Chart Objects ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../Libraries/x-saherelm.x-pivot.analysis.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.lib.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// +#include +#include +#include +#include +#include +#include + +// +// Definitions ... + +enum ENUM_XCHARTOBJECTS +{ + // + // Global ... + X_EMPTY_OBJ = 7860, // Empty + X_BOX_OBJ = 7861, // XBox + X_BAR_ARROW_OBJ = 7862, // XBarArrow + X_SIGNAL_OBJ = 8860, // XSignal + X_OHCL_OBJ = 8863, // XBar + X_RR_OBJ = 8864, // XRR + X_POSITION_OBJ = 8865, // XPosition + // + // 9860 Custom Object ... +}; + +enum ENUM_X_CHART_IDS +{ + X_AT, // AT + X_TO, // TO + X_FROM, // FROM + X_UPPER, // UPPER + X_LOWER, // LOWER + X_ENTRY, // ENTRY + X_TARGET, // TARGET + X_SL, // SL + X_TP, // TP + X_BAR_H_SHW, // HSHW + X_BAR_BDY, // BODY + X_BAR_L_SHW, // LSHW +}; + +string ToString(ENUM_X_CHART_IDS value) +{ + // + string result = NULL; + + // + result = EnumToString(value); + + // + return result; +} + +string ToXString(ENUM_XCHARTOBJECTS value) +{ + // + return EnumToString(value); +} + +struct XPOIStyle +{ + // + // Properties ... + int width; // Width ... + color clr; // Color ... + bool fill; // Fill, Use in Rectangles ... + ENUM_LINE_STYLE style; // Line Style ... + + // + // Constructor ... + XPOIStyle() + { + Default(); + } + + // + // Tools ... + + // + // Cleanup Model ... + void Clean() + { + // + width = 1; + fill = false; + clr = CLR_NONE; + style = STYLE_SOLID; + + // + ZeroMemory(this); + } + + // + // Default Props ... + void Default() + { + // + width = 1; + fill = false; + clr = CLR_NONE; + style = STYLE_SOLID; + } +}; + +// +// Extensions ... + +/** + * Converts a XBoxZone struct to XSignal instance ... + * + * @param box: XBoxZone instance reference, provide source info ... + * @param signal: XSignal instance reference, holds prepared converted signal ... + * + * @return ( bool ) + */ +bool ToXSignal( + XBoxZone &box, + XSignal &signal, + double &rewardRatios[], + double additionalSL = 0 // +) +{ + // + bool result = false; + + // + signal.Clean(); + + // + result = box.IsValid() && + HasChild(rewardRatios); + if (!result) + { + return result; + } + + // + XOHCL entryBar; + int entryIDX = box.ToIndex(); + if (entryIDX > 0) + { + entryIDX--; + } + result = entryBar.Init( + box.symbol, + box.period, + entryIDX // + ); + if (!result) + { + // + entryBar.Clean(); + + // + return result; + } + + // + bool isBullish = box.IsBullish(); + bool isBearish = box.IsBearish(); + + // + ENUM_POSITION_TYPE iType = + isBullish + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + ENUM_X_POSITION_TYPES iXType = + isBullish + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + + // + double points = GetPoints(box.symbol); + + // + double entry = + isBullish + ? box.upper + : box.lower; + entry = entryBar.open; + + // + double sl = + isBullish + ? box.lower + : box.upper; + if (additionalSL > 0) + { + // + sl = + isBullish + ? sl - additionalSL + : sl + additionalSL; + } + + // + double risk = MathAbs(entry - sl); + + // + double tp = 0; + + // + // Calculate Target ... + XTarget targets[]; + + // + double tmp[]; + int idx = -1; + XTarget iTarget; + bool has = false; + double iRatio = 0; + double iReward = 0; + double iRewardPrice = 0; + Copy( + rewardRatios, + tmp // + ); + while (HasChild(tmp)) + { + // + idx = -1; + iRatio = GetMaxWidthIndex( + tmp, + idx // + ); + + // + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + has = iRatio > 0; + + // + ArrayRemove( + tmp, + idx, + 1 // + ); + + // + bool canSetTP = tp <= 0; + + // + iReward = iRatio * risk; + + // + iRewardPrice = + isBullish + ? entry + iReward + : entry - iReward; + if (canSetTP) + { + tp = iRewardPrice; + } + else + { + // + iTarget.target = iRewardPrice; + AddRef( + iTarget, + targets // + ); + + // + iTarget.Clean(); + } + } + Clean(tmp); + + // + // Filling Signal ... + signal.tp = tp; + signal.sl = sl; + signal.type = iType; + signal.comment = ""; + signal.entry = entry; + signal.time = box.to; + signal.volume = 0.01; + signal.provider = box.type; + signal.symbol = box.symbol; + signal.period = box.period; + signal.mode = X_ORDER_MODE_MARKET; + + // + if (HasChild(targets)) + { + // + Copy( + targets, + signal.targets // + ); + } + + // + result = signal.IsValid(); + + // + // Cleanup Resources ... + + // + if (!result) + { + signal.Clean(); + } + + // + Clean(tmp); + Clean(targets); + iTarget.Clean(); + entryBar.Clean(); + + // + return result; +} + +/** + * Converts a Signal to Position ... + * + * @param signal: XSignal, reference to Specified Signal ... + * @param position: XPosition, reference to Generated Position ... + * @param magic: ulong, Specified Magic Number ... + * @param ticket: ulong, Specified Position Ticket ... + * + * @return ( bool ) + */ +bool ToXPosition( + XSignal &signal, + XPosition &position, + ulong magic = 0, + ulong ticket = 0 // +) +{ + // + bool result = false; + + // + // Prepare ... + position.Clean(); + + // + // Validate ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + // Normalize ... + + // + if (ticket <= 0) + { + // + if (signal.positionId > 0) + { + ticket = signal.positionId; + } + else + { + // + ticket = MathRand(); + signal.positionId = ticket; + } + } + signal.positionId = ticket; + + // + if (magic <= 0) + { + magic = MathRand(); + } + + // + // Filling Position ... + position.swap = 0; + position.profit = 0; + position.magic = magic; + position.commission = 0; + position.tp = signal.tp; + position.sl = signal.sl; + position.ticket = ticket; + position.type = signal.type; + position.price = signal.entry; + position.entry = signal.entry; + position.openAt = signal.time; + position.volume = signal.volume; + position.symbol = signal.symbol; + position.period = signal.period; + position.comment = signal.comment; + position.provider = signal.provider; + + // + result = position.IsValid(); + + // + // Cleanup Resources ... + if (!result) + { + position.Clean(); + } + + // + return result; +} + +/** + * Update Specified Position by Bar ... + * + * @param position: XPosition, reference to Specified Position ... + * @param barIndex: int, Specified Bar Index ... + * + * @return ( bool ) + */ +bool XUpdatePosition( + XPosition &position, + int barIndex = 0 // +) +{ + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeInt(barIndex, 0); + + // + // Validate ... + result = position.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL bar; + result = bar.Init( + position.symbol, + position.period, + barIndex // + ); + if (!result) + { + return result; + } + + // + double entryDiff = MathAbs(position.entry - position.price); + bool isLong = IsLong(position.type); + bool isInProfit = isLong + ? position.price > position.entry + : position.price < position.entry; + bool isTargeted = + isLong + ? position.price >= position.tp + : position.price <= position.tp; + bool isStoped = + isLong + ? position.price <= position.sl + : position.price >= position.sl; + result = !isTargeted && !isStoped; + if (!result) + { + return result; + } + + // + double spread = GetSpread(position.symbol); + position.price = bar.close + + (isLong + ? spread + : (-1 * spread)); + entryDiff = MathAbs(position.entry - position.price); + isInProfit = isLong + ? position.price > position.entry + : position.price < position.entry; + result = position.IsValid(); + + // + // Cleanup Resources ... + bar.Clean(); + + // + return result; +} + +// +// Implementation ... + +// +// Global Chart Objects ... + +/** + * Base Chart Object ... + **/ +class XCBaseObject : public CChartObject +{ + // + public: + // + + // + // Getter(s) / Setter(s) ... + + /** + * Get Object Specified Name ... + * + * @return ( string ) + */ + string ObjName() + { + return mObjName; + } + + /** + * Set Object Specified Name ... + * + * @param value: String ... + */ + void ObjName(string value) + { + // + Name(value); + mObjName = value; + } + + virtual string TypeString() + { + return ToXString(X_EMPTY_OBJ); + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual int Type(void) const + { + return ((int)X_EMPTY_OBJ); + } + + /** + * Destroy ... + */ + void virtual Destroy() + { + // + Detach(); + Delete(); + } + + // + private: + // + + // + // Props ... + string mObjName; // Object Specified Name ... + + // +}; + +/** + * Bar Arrow Object ... + **/ +class XCBarArrowObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param name: String, Specified Object ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param swing: XCSwing instance ... + * + * @return ( bool ) + */ + bool CreateByBar( + long chart_id, + string name, + int window, + int arrow, + XOHCL &bar, + ENUM_X_PRICE priceType, + double threshold = 5 // + ) + { + // + bool result = false; + + // + result = + // + bar.IsValid() && + IsValid(name) + // + ; + if (!result) + { + return result; + } + + // + datetime time = bar.time; + double price = bar.GetPrice(priceType); + + // + if (threshold > 0) + { + // + double thresholdPrice = threshold * GetPoints(bar.symbol); + if (priceType == X_PRICE_HIGH) + { + price += thresholdPrice; + } + else if (priceType == X_PRICE_LOW) + { + price -= thresholdPrice; + } + } + + // + result = mArrow.Create( + chart_id, + name, + window, + time, + price, + (char)arrow // + ); + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Virtual ... + + /** + * Destroy ... + */ + void virtual Destroy() + { + // + mArrow.Detach(); + mArrow.Delete(); + + // + Detach(); + Delete(); + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual int Type(void) + { + return (int)X_BAR_ARROW_OBJ; + } + + /** + * Type as String ... + **/ + string TypeString() override + { + return ToXString(X_BAR_ARROW_OBJ); + } + + // + // Setter(s) ... + + /** + * Set Arrow Anchor ... + * + * @param value: ENUM_ARROW_ANCHOR member ... + */ + void ArrowAnchor(ENUM_ARROW_ANCHOR value) + { + mArrow.Anchor(value); + } + + /** + * Set Arrow Color ... + * + * @param value: Color ... + */ + void ArrowColor(color value) + { + mArrow.Color(value); + } + + /** + * Set Arrow Width ... + * + * @param value: Integer ... + */ + void ArrowWidth(int value) + { + mArrow.Width(value); + } + + // + private: + // + CChartObjectArrow mArrow; + + // +}; + +/** + * Signal Object ... + **/ +class XCSignalObject : public XCBaseObject +{ + // + public: + // + + // + // Constructor ... + XCSignalObject() + { + } + + // + // Deconstructor ... + ~XCSignalObject() + { + } + + /** + * Create a Signal Object on Chart ... + * + * @param chart_id: Long ... + * @param name: String ... + * @param window: Integer ... + * @param signal: XSignal instance ... + * @param length: int, Specified Length of Signal ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + const int window, + XSignal &signal, + int length = 3, + string prefix = NULL // + ) + { + // + bool result = false; + + // + length = NormalizeInt(length, 3); + + // + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + string name = signal.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + int delay = (PeriodSeconds(signal.period) * length); + datetime time1 = (datetime)((int)signal.time - delay); + datetime time2 = (datetime)((int)signal.time + delay); + + // + // TP ... + string tpName = ToString(X_TP) + "_" + nameMD5; + result = mTPTrend.Create( + chart_id, + tpName, + window, + time1, + signal.tp, + time2, + signal.tp // + ); + if (!result) + { + return result; + } + + // + // SL ... + string slName = ToString(X_SL) + "_" + nameMD5; + result = mSLTrend.Create( + chart_id, + slName, + window, + time1, + signal.sl, + time2, + signal.sl // + ); + if (!result) + { + // + mTPTrend.Delete(); + return result; + } + + // + // TARGET ... + bool hasTargets = HasChild(signal.targets); + if (hasTargets) + { + // + int targetsCount = ArraySize(signal.targets); + for (int i = 0; i < targetsCount; i++) + { + // + string targetName = ToString(X_TARGET) + "_" + ToXString(i) + "_" + nameMD5; + CChartObjectTrend *mTargetTrend; + mTargetTrend = new CChartObjectTrend(); + result = mTargetTrend.Create( + chart_id, + targetName, + window, + time1, + signal.targets[i].target, + time2, + signal.targets[i].target // + ); + if (!result) + { + // + mTPTrend.Delete(); + mSLTrend.Delete(); + break; + } + + // + mTargetTrends.Add(mTargetTrend); + } + } + + // + // ENTRY ... + string entrName = ToString(X_ENTRY) + "_" + nameMD5; + result = mEntryTrend.Create( + chart_id, + entrName, + window, + time1, + signal.entry, + time2, + signal.entry // + ); + if (!result) + { + // + mTPTrend.Delete(); + mSLTrend.Delete(); + mTargetTrends.Clear(); + return result; + } + + // + // Set Object Name ... + ObjName(name); + + // + return result; + } + + // + // Virtual ... + + /** + * Destroy ... + */ + void virtual Destroy() + { + // + mTPTrend.Detach(); + mTPTrend.Delete(); + mSLTrend.Detach(); + mSLTrend.Delete(); + mEntryTrend.Detach(); + mEntryTrend.Delete(); + + // + mTargetTrends.Clear(); + + // + Detach(); + Delete(); + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual int Type(void) + { + return (int)X_SIGNAL_OBJ; + } + + /** + * Type as String ... + **/ + string TypeString() override + { + return ToXString(X_SIGNAL_OBJ); + } + + // + // Setter(s) ... + + // + // TP ... + + /** + * Set TP Width ... + * + * @param value: Integer ... + */ + void TPWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mTPTrend.Width(value); + } + + /** + * Set TP Color ... + * + * @param value: Color ... + */ + void TPColor(color value) + { + mTPTrend.Color(value); + } + + /** + * Set TP Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void TPStyle(ENUM_LINE_STYLE value) + { + mTPTrend.Style(value); + } + + // + // SL ... + + /** + * Set SL Width ... + * + * @param value: Integer ... + */ + void SLWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mSLTrend.Width(value); + } + + /** + * Set SL Color ... + * + * @param value: Color ... + */ + void SLColor(color value) + { + mSLTrend.Color(value); + } + + /** + * Set SL Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void SLStyle(ENUM_LINE_STYLE value) + { + mSLTrend.Style(value); + } + + // + // TARGET ... + + /** + * Set Target Width ... + * + * @param value: Integer ... + */ + void TargetWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + for (int i = 0; i < mTargetTrends.Total(); i++) + { + // + CChartObjectTrend *iTrend = (CChartObjectTrend *)mTargetTrends.At(i); + iTrend.Width(value); + } + } + + /** + * Set Target Color ... + * + * @param value: Color ... + */ + void TargetColor(color value) + { + // + for (int i = 0; i < mTargetTrends.Total(); i++) + { + // + CChartObjectTrend *iTrend = (CChartObjectTrend *)mTargetTrends.At(i); + iTrend.Color(value); + } + } + + /** + * Set Target Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void TargetStyle(ENUM_LINE_STYLE value) + { + // + for (int i = 0; i < mTargetTrends.Total(); i++) + { + // + CChartObjectTrend *iTrend = (CChartObjectTrend *)mTargetTrends.At(i); + iTrend.Style(value); + } + } + + // + // ENTRY ... + + /** + * Set Entry Width ... + * + * @param value: Integer ... + */ + void EntryWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mEntryTrend.Width(value); + } + + /** + * Set Entry Color ... + * + * @param value: Color ... + */ + void EntryColor(color value) + { + mEntryTrend.Color(value); + } + + /** + * Set Entry Style ... + * + * @param value: ENUM_LINE_STYLE ... + */ + void EntryStyle(ENUM_LINE_STYLE value) + { + mEntryTrend.Style(value); + } + + // + private: + // + + // + CChartObjectTrend mTPTrend; + CChartObjectTrend mSLTrend; + CChartObjectTrend mEntryTrend; + CArrayObj mTargetTrends; +}; + +/** + * XRR Object ... + **/ +class XCRRObject : public XCSignalObject +{ + // + // Public ... + public: + // + // Constructor ... + bool CreateBoxRR( + long chart_id, + const int window, + XBoxZone &box, + double &rewardRatios[], + int length = 3, + string prefix = NULL // + ) + { + // + bool result = false; + + // + length = NormalizeInt(length, 3); + + // + result = box.IsValid(); + if (!result) + { + return result; + } + + // + XSignal signal; + result = ToXSignal( + box, + signal, + rewardRatios // + ); + if (!result) + { + // + signal.Clean(); + + // + return result; + } + + // + result = Create( + chart_id, + window, + signal, + length, + prefix // + ); + + // + signal.Clean(); + + // + return result; + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual int Type(void) + { + return (int)X_RR_OBJ; + } + + /** + * Type as String ... + **/ + string TypeString() override + { + return ToXString(X_RR_OBJ); + } +}; + +/** + * XOHCL Object ... + **/ +class XCOHCLObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param pivot: XPVPivot instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XOHCL &bar, + datetime to, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = bar.IsValid() && + IsValid(to); + if (!result) + { + return result; + } + + // + string name = bar.GetTag(); + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + // High Shadow ... + string hShadowName = ToString(X_BAR_H_SHW) + "_" + nameMD5; + + // + result = mHighShadowRect.Create( + chart_id, + hShadowName, + window, + bar.time, + bar.high, + to, + bar.GetUp() // + ); + if (!result) + { + return result; + } + + // + // Body ... + string bodyName = ToString(X_BAR_BDY) + "_" + nameMD5; + + // + result = mBodyRect.Create( + chart_id, + bodyName, + window, + bar.time, + bar.GetUp(), + to, + bar.GetDown() // + ); + if (!result) + { + // + mHighShadowRect.Delete(); + mHighShadowRect.Detach(); + return result; + } + + // + // Low Shadow ... + string lShadowName = ToString(X_BAR_L_SHW) + "_" + nameMD5; + + // + result = mLowShadowRect.Create( + chart_id, + lShadowName, + window, + bar.time, + bar.GetDown(), + to, + bar.low // + ); + if (!result) + { + // + mBodyRect.Delete(); + mBodyRect.Detach(); + mHighShadowRect.Delete(); + mHighShadowRect.Detach(); + return result; + } + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Virtual ... + + /** + * Destroy ... + */ + void virtual Destroy() + { + // + mBodyRect.Detach(); + mBodyRect.Delete(); + + // + mLowShadowRect.Detach(); + mLowShadowRect.Delete(); + + // + mHighShadowRect.Detach(); + mHighShadowRect.Delete(); + + // + Detach(); + Delete(); + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual int Type(void) + { + return (int)X_OHCL_OBJ; + } + + /** + * Type as String ... + **/ + string TypeString() override + { + return ToXString(X_OHCL_OBJ); + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set High Shadow Width ... + * + * @param value: Integer ... + */ + void HighShadowWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mHighShadowRect.Width(value); + } + + /** + * Set High Shadow Color ... + * + * @param value: Color ... + */ + void HighShadowColor(color value) + { + mHighShadowRect.Color(value); + } + + /** + * Set High Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void HighShadowStyle(ENUM_LINE_STYLE value) + { + mHighShadowRect.Style(value); + } + + /** + * Set High Shadow Fill ... + * + * @param value: Boolean ... + */ + void HighShadowFill(bool value) + { + mHighShadowRect.Fill(value); + } + + /** + * Set Body Width ... + * + * @param value: Integer ... + */ + void BodyWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mBodyRect.Width(value); + } + + /** + * Set Body Color ... + * + * @param value: Color ... + */ + void BodyColor(color value) + { + mBodyRect.Color(value); + } + + /** + * Set Body Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BodyStyle(ENUM_LINE_STYLE value) + { + mBodyRect.Style(value); + } + + /** + * Set Body Fill ... + * + * @param value: Boolean ... + */ + void BodyFill(bool value) + { + mBodyRect.Fill(value); + } + + /** + * Set Low Shadow Width ... + * + * @param value: Integer ... + */ + void LowShadowWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mLowShadowRect.Width(value); + } + + /** + * Set Low Shadow Color ... + * + * @param value: Color ... + */ + void LowShadowColor(color value) + { + mLowShadowRect.Color(value); + } + + /** + * Set Low Shadow Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void LowShadowStyle(ENUM_LINE_STYLE value) + { + mLowShadowRect.Style(value); + } + + /** + * Set Low Shadow Fill ... + * + * @param value: Boolean ... + */ + void LowShadowFill(bool value) + { + mLowShadowRect.Fill(value); + } + + void BarSpes( + int width = 1, + color clr = clrNONE, + ENUM_LINE_STYLE style = STYLE_SOLID, + bool fill = false // + ) + { + // + BodyWidth(width); + LowShadowWidth(width); + HighShadowWidth(width); + + // + BodyColor(clr); + LowShadowColor(clr); + HighShadowColor(clr); + + // + BodyStyle(style); + LowShadowStyle(style); + HighShadowStyle(style); + + // + BodyFill(fill); + LowShadowFill(fill); + HighShadowFill(fill); + } + + // + private: + // + + // + // Props ... + CChartObjectRectangle mHighShadowRect; + CChartObjectRectangle mBodyRect; + CChartObjectRectangle mLowShadowRect; +}; + +/** + * Box Object ... + **/ +class XCBoxObject : public XCBaseObject +{ + // + public: + // + + /** + * Creator ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param pivot: XPVPivot instance ... + * @param prefix: String ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + string name, + double upper, + double lower, + datetime from, + datetime to, + datetime at = NULL, + string prefix = NULL // + ) + { + // + bool result = false; + + // + result = + upper > 0 && + lower > 0 && + to > from && + IsValid(to) && + IsValid(name) && + IsValid(from) && + upper > lower; + if (!result) + { + return result; + } + + // + if (IsValid(prefix)) + { + name = prefix + "_" + name; + } + string nameMD5 = ToMD5(name); + + // + result = mRect.Create( + chart_id, + name, + window, + from, + upper, + to, + lower // + ); + if (!result) + { + return result; + } + + // + if (result) + { + // + if (IsValid(at)) + { + // + result = mAt.Create( + chart_id, + name + ToString(X_AT), + window, + at // + ); + } + + // + if (!result) + { + // + mAt.Detach(); + mAt.Delete(); + + // + mRect.Detach(); + mRect.Delete(); + } + } + + // + if (result) + { + ObjName(name); + } + + // + return result; + } + + // + // Virtual ... + + /** + * Destroy ... + */ + void virtual Destroy() + { + // + mAt.Detach(); + mAt.Delete(); + + // + mRect.Detach(); + mRect.Delete(); + + // + Detach(); + Delete(); + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + virtual int Type(void) + { + return (int)X_BOX_OBJ; + } + + /** + * Type as String ... + **/ + string TypeString() override + { + return ToXString(X_BOX_OBJ); + } + + // + // Getter(s) / Setter(s) ... + + /** + * Set Width ... + * + * @param value: Integer ... + */ + void BoxWidth(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mAt.Width(value); + mRect.Width(value); + } + + /** + * Set Color ... + * + * @param value: Color ... + */ + void BoxColor(color value) + { + // + mAt.Color(value); + mRect.Color(value); + } + + /** + * Set Style ... + * + * @param value: ENUM_LINE_STYLE member ... + */ + void BoxStyle(ENUM_LINE_STYLE value) + { + // + mAt.Style(value); + mRect.Style(value); + } + + /** + * Set Fill ... + * + * @param value: Boolean ... + */ + void BoxFill(bool value) + { + mRect.Fill(value); + } + + // + private: + // + + // + // Props ... + CChartObjectVLine mAt; + CChartObjectRectangle mRect; +}; + +/** + * Position Object ... + **/ +class XCPositionObject : public XCBaseObject +{ + // + // Public ... + public: + // + XPOIStyle riskStyle; // Risk Box Style ... + color inProfitColor; // In Profit Price Box Color ... + color inDrawdownColor; // In Drawdown Price Box Color ... + XPOIStyle rewardStyle; // Reward Box Style ... + ENUM_LINE_STYLE priceStyle; // Price Box Style ... + + // + // Creators ... + + /** + * Create a Position Object by Signal reference ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param signal: XSignal, reference to Provided Signal ... + * @param magic: ulong, Specified Position Magic Number ... + * @param ticket: ulong, Specified Position Ticket ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XSignal &signal, + ulong magic = 0, + ulong ticket = 0 // + ) + { + // + bool result = false; + + // + // Converts Signal to Test Position ... + XPosition _position; + result = ToXPosition( + signal, + _position, + magic, + ticket // + ); + + // + // Validate ... + result = chart_id >= 0 && + window >= 0 && + _position.IsValid(); + if (!result) + { + return result; + } + + // + result = Create( + chart_id, + window, + _position // + ); + + // + return result; + } + + /** + * Create a Position Object ... + * + * @param chart_id: Long, Specified Chart ID ... + * @param window: Integer, Specified Chart Window ID ... + * @param position: XPosition, reference to Specified Position ... + * + * @return ( bool ) + */ + bool Create( + long chart_id, + int window, + XPosition &position // + ) + { + // + bool result = false; + + // + // Validate ... + result = chart_id >= 0 && + window >= 0 && + position.IsValid(); + if (!result) + { + return result; + } + + // + result = Update(position); + if (!result) + { + // + Destroy(); + return result; + } + + // + return result; + } + + /** + * Update Position if Belongs to ... + * + * @param position: XPosition, reference to Specified Position ... + * @param barIndex: int, Specified Bar Index ... + * + * @return ( bool ) + */ + bool Update( + XPosition &position, + int barIndex = 0 // + ) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeInt(barIndex, 0); + + // + // Validate ... + result = + mChartID >= 0 && + mWindowID >= 0 && + position.IsValid() && + (!HasPosition() + ? true + : IsBelong(position)); + if (!result) + { + return result; + } + + // + datetime _toTime = GetBarTime( + position.symbol, + position.period, + barIndex // + ); + + // + // Validate Chart Info ... + result = UpdatePosition( + position, + _toTime // + ); + + // + return result; + } + + /** + * Update Position if Belongs to ... + * + * @param barIndex: int, Specified Bar Index ... + * + * @return ( bool ) + */ + bool Update(int barIndex = 0) + { + // + bool result = false; + + // + // Normalize ... + barIndex = NormalizeInt(barIndex, 0); + + // + // Validate ... + result = HasPosition(); + if (!result) + { + return result; + } + + // + // Update mPosition ... + result = XUpdatePosition(mPosition, barIndex); + if (!result) + { + return result; + } + + // + result = Update( + mPosition, + barIndex // + ); + + // + return result; + } + + // + // Retrievers ... + + bool GetPosition(XPosition &_position) + { + // + bool result = false; + + // + // Prepare ... + _position.Clean(); + + // + // Validate ... + result = HasPosition(); + if (!result) + { + return result; + } + + // + _position = mPosition; + + // + return result; + } + + // + // Checkers ... + + /** + * Check Object is Belongs to Specified Position or not ... + * + * @param position: XPosition, reference to Specified Position ... + * + * @return ( bool ) + */ + bool IsBelong(XPosition &position) + { + // + bool result = false; + + // + // Validate ... + result = + HasPosition() && + position.IsValid(); + + // + // Check ... + result = + result && + mPosition.ticket == position.ticket; + + // + return result; + } + + // + // Overrides ... + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + string TypeString() override + { + return ToXString(X_POSITION_OBJ); + } + + /** + * Retrieve Object Type ... + * + * @return ( ENUM_XCHARTOBJECTS ) + */ + int Type(void) const override + { + return ((int)X_POSITION_OBJ); + } + + /** + * Destroy Object ... + **/ + void Destroy() override + { + // + ObjName(NULL); + + // + mRiskBox.Clean(); + mPosition.Clean(); + mPriceBox.Clean(); + mRewardBox.Clean(); + + // + mRiskBoxObj.Detach(); + mRiskBoxObj.Delete(); + + // + mPriceBoxObj.Detach(); + mPriceBoxObj.Delete(); + + // + mRewardBoxObj.Detach(); + mRewardBoxObj.Delete(); + } + + // + // Stylers ... + + /** + * Apply Styles based on Current Style Configurations ... + */ + void ApplyStyle() + { + // + // Validate ... + bool has = HasPosition(); + if (!has) + { + return; + } + + // + // Check Position in Profit ... + bool isLong = IsLong(mPosition.type); + bool isRiskFreed = + isLong + ? mPosition.sl > mPosition.entry + : mPosition.sl < mPosition.entry; + bool isInProfit = mPosition.profit > 0; + XPOIStyle _priceStyle; + if (isInProfit) + { + // + _priceStyle = rewardStyle; + _priceStyle.clr = inProfitColor; + } + else + { + // + _priceStyle = riskStyle; + _priceStyle.clr = inDrawdownColor; + } + + // + // Apply Profit Based Styles ... + _priceStyle.fill = true; + _priceStyle.style = priceStyle; + + // + // Change Risk Style if Risk Freed Position ... + if (isRiskFreed) + { + // + riskStyle.fill = true; + riskStyle.clr = rewardStyle.clr; + } + + // + // Risk Style ... + mRiskBoxObj.BoxColor(riskStyle.clr); + mRiskBoxObj.BoxFill(riskStyle.fill); + mRiskBoxObj.BoxStyle(riskStyle.style); + mRiskBoxObj.BoxWidth(riskStyle.width); + + // + // Reward Style ... + mRewardBoxObj.BoxColor(rewardStyle.clr); + mRewardBoxObj.BoxFill(rewardStyle.fill); + mRewardBoxObj.BoxStyle(rewardStyle.style); + mRewardBoxObj.BoxWidth(rewardStyle.width); + + // + // Price Style .. + mPriceBoxObj.BoxColor(_priceStyle.clr); + mPriceBoxObj.BoxFill(_priceStyle.fill); + mPriceBoxObj.BoxStyle(_priceStyle.style); + mPriceBoxObj.BoxWidth(_priceStyle.width); + + // + // Cleanup Resources ... + _priceStyle.Clean(); + } + + // + void ApplyStyle( + XPOIStyle &bullishStyle, + XPOIStyle &bearishStyle // + ) + { + // + // Validate ... + if (!HasPosition()) + { + return; + } + + // + // Risk Box ... + if (mRiskBox.IsValid()) + { + // + mRiskBoxObj.BoxColor(bearishStyle.clr); + mRiskBoxObj.BoxFill(bearishStyle.fill); + mRiskBoxObj.BoxStyle(bearishStyle.style); + mRiskBoxObj.BoxWidth(bearishStyle.width); + } + + // + // Reward Box ... + if (mRewardBox.IsValid()) + { + // + mRewardBoxObj.BoxColor(bullishStyle.clr); + mRewardBoxObj.BoxFill(bullishStyle.fill); + mRewardBoxObj.BoxStyle(bullishStyle.style); + mRewardBoxObj.BoxWidth(bullishStyle.width); + } + + // + // Price Box ... + if (mPriceBox.IsValid()) + { + // + XPOIStyle _priceStyle; + if (mPriceBox.IsBullish()) + { + _priceStyle = bullishStyle; + } + else + { + _priceStyle = bearishStyle; + } + + // + mPriceBoxObj.BoxColor(_priceStyle.clr); + mPriceBoxObj.BoxFill(_priceStyle.fill); + mPriceBoxObj.BoxStyle(_priceStyle.style); + mPriceBoxObj.BoxWidth(_priceStyle.width); + + // + _priceStyle.Clean(); + } + } + + // + // Protected ... + protected: + // + + // + bool HasPosition() + { + return mPosition.IsValid(); + } + + // + bool UpdatePosition( + XPosition &_position, + datetime _toTime = NULL // + ) + { + // + bool result = false; + + // + // Normalize ... + _toTime = NormalizeTime(_toTime); + + // + // Validate ... + result = _position.IsValid() && + (!HasPosition() + ? true + : _position.ticket == mPosition.ticket // + ); + if (!result) + { + return result; + } + + // + mPosition = _position; + result = UpdateZones(_toTime); + + // + return result; + } + + // + bool UpdateZones(datetime _toTime = NULL) + { + // + bool result = false; + + // + // Normalize ... + _toTime = NormalizeTime(_toTime); + + // + // Validate ... + result = HasPosition(); + if (!result) + { + return result; + } + + // + string iSymbol = mPosition.symbol; + ENUM_TIMEFRAMES iPeriod = mPosition.period; + + // + datetime iAt = mPosition.openAt; + datetime iFrom = mPosition.openAt; + + // + datetime _defaultToTime = iFrom + (PeriodSeconds(iPeriod) * 3); + datetime iTo = _toTime <= _defaultToTime + ? _defaultToTime + : _toTime; + + // + double iTP = mPosition.tp; + double iSL = mPosition.sl; + double iEntry = mPosition.entry; + double iPrice = mPosition.price; + + // + bool isLong = IsLong(mPosition.type); + ENUM_X_DIRECTION iRiskDir = isLong + ? X_DIRECTION_BEARISH + : X_DIRECTION_BULLISH; + ENUM_X_DIRECTION iRewardDir = isLong + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + bool isInProfit = mPosition.profit > 0; + bool isRiskFreed = + isLong + ? mPosition.sl > mPosition.entry + : mPosition.sl < mPosition.entry; + ENUM_X_DIRECTION iPriceDir = isInProfit + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + // Try to Update Zones ... + string iSuffix = ToXString(mPosition.type) + "_" + ToXString(mPosition.ticket); + string iPrefix = ToXString(TimeToSeconds(mPosition.openAt)); + string iName = iSuffix + "_" + iPrefix; + string iRiskName = iSuffix + "_" + "RISK" + "_" + iPrefix; + string iPriceName = iSuffix + "_" + "PRICE" + "_" + iPrefix; + string iRewardName = iSuffix + "_" + "REWARD" + "_" + iPrefix; + + // + // Risk Box ... + mRiskBox.to = iTo; + mRiskBox.at = iAt; + mRiskBox.lower = + isLong + ? isRiskFreed + ? iEntry + : iSL + : isRiskFreed + ? iSL + : iEntry; + mRiskBox.upper = + isLong + ? isRiskFreed + ? iSL + : iEntry + : isRiskFreed + ? iEntry + : iSL; + mRiskBox.from = iFrom; + mRiskBox.symbol = iSymbol; + mRiskBox.period = iPeriod; + mRiskBox.type = iRiskName; + mRiskBox.dir = isRiskFreed + ? X_DIRECTION_BEARISH + : X_DIRECTION_BULLISH; + + // + // Reward Box ... + mRewardBox.to = iTo; + mRewardBox.at = iAt; + mRewardBox.lower = + isLong + ? iEntry + : iTP; + mRewardBox.upper = + isLong + ? iTP + : iEntry; + mRewardBox.from = iFrom; + mRewardBox.symbol = iSymbol; + mRewardBox.period = iPeriod; + mRewardBox.type = iRewardName; + mRewardBox.dir = X_DIRECTION_BULLISH; + + // + // Price Box ... + mPriceBox.to = iTo; + mPriceBox.at = iAt; + mPriceBox.lower = + isLong + ? isInProfit + ? isRiskFreed + ? iSL + : iEntry + : iPrice + : isInProfit + ? isRiskFreed + ? iSL + : iPrice + : iEntry; + mPriceBox.upper = + isLong + ? isInProfit + ? iPrice + : iEntry + : isInProfit + ? iEntry + : iPrice; + mPriceBox.from = iFrom; + mPriceBox.symbol = iSymbol; + mPriceBox.period = iPeriod; + mPriceBox.type = iPriceName; + mPriceBox.dir = isInProfit + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + result = mRiskBox.IsValid() && + mPriceBox.IsValid() && + mRewardBox.IsValid(); + if (!result) + { + return result; + } + + // + mRiskBoxObj.Detach(); + mRiskBoxObj.Delete(); + bool isRiskCreated = + mRiskBoxObj.Create( + mChartID, + mWindowID, + mRiskBox.type, + mRiskBox.upper, + mRiskBox.lower, + mRiskBox.from, + mRiskBox.to, + NULL, // At ... + NULL // Prefix ... + ); + + // + mRewardBoxObj.Detach(); + mRewardBoxObj.Delete(); + bool isRewardCreated = + mRewardBoxObj.Create( + mChartID, + mWindowID, + mRewardBox.type, + mRewardBox.upper, + mRewardBox.lower, + mRewardBox.from, + mRewardBox.to, + NULL, // At ... + NULL // Prefix ... + ); + + // + mPriceBoxObj.Detach(); + mPriceBoxObj.Delete(); + bool isPriceCreated = + mPriceBoxObj.Create( + mChartID, + mWindowID, + mPriceBox.type, + mPriceBox.upper, + mPriceBox.lower, + mPriceBox.from, + mPriceBox.to, + NULL, // At ... + NULL // Prefix ... + ); + + // + result = + isRiskCreated && + isPriceCreated && + isRewardCreated; + if (result) + { + // + ObjName(iName); + + // + // Apply Styles ... + ApplyStyle(); + } + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + int mWindowID; + long mChartID; + + // + XBoxZone mRiskBox; + XBoxZone mPriceBox; + XPosition mPosition; + XBoxZone mRewardBox; + + // + XCBoxObject mRiskBoxObj; + XCBoxObject mPriceBoxObj; + XCBoxObject mRewardBoxObj; + + // +}; + +// +// Extensions ... + +/** + * Add all Items of Specified CArrayObj into another ... + * + * @param source: CArrayObj, pointer refrence Specified Data Source ... + * @param dest: CArrayObj, pointer refrence Specified Destination of Adding ... + */ +void AddObjects( + CArrayObj *&source, + CArrayObj &dest // +) +{ + // + bool has = source != NULL && + source.Total() > 0; + if (!has) + { + return; + } + + // + for (int i = 0; i < source.Total(); i++) + { + dest.Add(source.At(i)); + } +} + +/** + * Remove Drawn Objects from Chart ... + * + * @param tag: Specified Object Name, if NULL remove all Objects ... + * @param chartId: long, Specified Chart ... + * @param subWindow: int Specified Sub Window ... + */ +void RemoveObjects( + string tag = NULL, + long chartId = -1, + int subWindow = -1 // +) +{ + // + // Normalize Args ... + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + bool has = false; + string iName = NULL; + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + // Retrieve Object Name ... + iName = ObjectName(chartId, iObj, subWindow); + + // + // Check Can Delete Object or not ... + has = + !IsSpecifiedValid(tag) + ? true + : StringFind(iName, tag) >= 0; + if (has) + { + ObjectDelete(chartId, iName); + } + } + + // + // Redraw Chart ... + ChartRedraw(); +} + +// +// Color Manipulation Functions ... + +/** + * Apply Alph to Color ... + * + * @param _clr: Specified Color ... + * @param _alpha: Specified Alpha to Apply ... + * + * @return ( color ) + */ +color ApplyAlpha( + color _clr, + uchar _alpha = 255 // +) +{ + // + color result = _clr; + + // + // Normalize ... + _alpha = (uchar)NormalizeInt(_alpha, 0, 255); + + // + uchar alpha = _alpha / 255; + + // + uint uintColor = ColorToARGB(_clr, alpha); + result = (color)uintColor; + + // + return result; +} + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-data.collector.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// ------------------------------------------------- +// Name: XCDataCollector ... +// Description: Class for Handling Data Read or Write ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm Class for Handling Data Read or Write" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" + +// +// Definitions ... + +// +// Implementation ... +class XCDataCollector : public XCBase +{ + // + // Public ... + public: + // + // Constructors ... + XCDataCollector() + { + mPath = "XDataCollector"; + } + + // + // Deconstructor ... + ~XCDataCollector() + { + } + + // + // Properties ... + + // + string Path() + { + return mPath; + } + + // + void Path(string value) + { + mPath = value; + } + + // + // Tools ... + + // + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + (IsValid(mPath) ? mPath + "\\" : "") + fileName + ".x121.log" + // + ; + + // + return result; + } + + // + int GetFileHandlerForWrite(string filePath) + { + // + int result = INVALID_HANDLE; + + // + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_WRITE | FILE_TXT // + ); + + // + return result; + } + + // + int GetFileHandlerForRead(string filePath) + { + // + int result = INVALID_HANDLE; + + // + if (!IsValid(filePath)) + { + return result; + } + + // + result = FileOpen( + filePath, + FILE_READ | FILE_TXT | FILE_ANSI // + ); + + // + return result; + } + + /** + * Save Specified Content into Specified File Name ... + * + * @param fileName: string, file name ... + * @param content: string, content ... + * + * @return ( bool ) + */ + bool Save( + string fileName, + string content // + ) + { + // + bool result = false; + + // + result = IsValid(fileName) && + IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetFileHandlerForWrite(fileName); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + /** + * Append Specified Content into Specified File Name ... + * + * @param fileName: string, file name ... + * @param content: string, content ... + * + * @return ( bool ) + */ + bool Append( + string fileName, + string content // + ) + { + // + bool result = false; + + // + result = IsValid(fileName) && + IsValid(content); + if (!result) + { + return result; + } + + // + int mHandler = GetFileHandlerForWrite(fileName); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + FileSeek(mHandler, 0, SEEK_END); + FileWrite(mHandler, content); + FileFlush(mHandler); + FileClose(mHandler); + + // + return result; + } + + /** + * Read Specified File Content ... + * + * @param fileName: string, file name ... + * @param content: string reference, hold's reading content ... + * + * @return ( bool ) + */ + bool Read( + string fileName, + string &content // + ) + { + // + bool result = false; + + // + // Normalize Args ... + content = NULL; + + // + // Validate Args ... + result = IsValid(fileName); + if (!result) + { + return result; + } + + // + int mHandler = GetFileHandlerForRead(fileName); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Reading File ... + while (!FileIsEnding(mHandler)) + { + // + string iLine = FileReadString(mHandler); + content += iLine; + } + + // + // Close File ... + FileClose(mHandler); + + // + return result; + } + + /** + * Read Specified File Content ... + * + * @param fileName: string, file name ... + * @param content: string reference collection, hold's reading content lines ... + * + * @return ( bool ) + */ + bool Read( + string fileName, + string &content[] // + ) + { + // + bool result = false; + + // + // Normalize Args ... + Clean(content); + + // + // Validate Args ... + result = IsValid(fileName); + if (!result) + { + return result; + } + + // + int mHandler = GetFileHandlerForRead(fileName); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + // Reading File ... + while (!FileIsEnding(mHandler)) + { + // + string iLine = FileReadString(mHandler); + Add( + iLine, + content // + ); + } + + // + // Close File ... + FileClose(mHandler); + + // + return result; + } + + /** + * Check Specified File Exists or not ... + * + * @param fileName: string, Full Path of File to Check ... + * + * @return ( bool ) + */ + bool IsExists(string fileName) + { + // + bool result = false; + + // + // Validate Args ... + result = IsValid(fileName); + if (!result) + { + return result; + } + + // + // Check File Exists or not ... + int mHandler = GetFileHandlerForRead(fileName); + result = mHandler != INVALID_HANDLE; + FileClose(mHandler); + + // + return result; + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + + // + string mPath; // Base Collector Path ... +}; + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-expert.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCBaseExpret ... +// Description: Base Expert Class ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm Base Expert Class" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-chart.helper.class.mq5" +#include "../Classes/x-saherelm.x-guard.class.mq5" +#include "../Classes/x-saherelm.x-position.drawer.class.mq5" +#include "../Classes/x-saherelm.x-signaller.class.mq5" +#include "../Classes/x-saherelm.x-target.class.mq5" +#include "../Classes/x-saherelm.x-trade-manager.class.mq5" +#include "../Classes/x-saherelm.x-volume.class.mq5" + +// +// Import Chart Objects ... +#include +#include +#include +#include + +// +// Definitions ... + +// +// Implementation ... +class XCBaseExpert : public XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + // Common ... + long eaMagicNumber; // Magic Number + int eaSlippage; // Slippgae + string eaLogSuffix; // Log Suffix + + // + // Symbol Configurations ... + string eaSymbolConfiguration; // Symbol Configurations ... + + // + // Management ... + bool eaAllowGuards; // Allow Guards + bool eaAllowTrade; // Allow Trade on Signals + bool eaAllowLongs; // Allow Long Trades + bool eaAllowShorts; // Allow Short Trades + double eaMaxAllowedDrawdownFactor; // Max Allowed DrawDown for Trade + + // + // Volume ... + ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect; // Volume Applying Type + double eaStaticVoluem; // Static Volume + double eaDynamicVolumeStepBalance; // Step of Balance for Increase Volume + double eaDynamicVolumeStepVolume; // Step of Volume Increasing + double eaConstantRiskBalance; // Constant Risk Balance per Trade + double eaConstantPercent; // Constant Percent of Balance Per Trade + double eaConstantBalance; // Constant Balance for Calculations + + // + // Alert ... + bool eaEnableAlerts; // Enable Alerts + bool eaSaveAlerts; // Save Alerts + bool eaLogAlerts; // Log Alerts + bool eaMailAlerts; // Mail Alerts + bool eaPushAlerts; // Push Alerts + bool eaTerminalAlerts; // Terminal Alerts + + // + // Reports ... + bool eaReportNewMonths; // Report New Month + bool eaReportNewWeeks; // Report New Weeks + bool eaReportNewDays; // Report New Days + bool eaReportNewHours; // Report New Hours + bool eaReportTrades; // Report Trades + bool eaReportSignals; // Report Signals + bool eaReportProtector; // Report Protector Actions + bool eaReportRestrictions; // Report Restrictions + bool eaReportAfterTradesBalance; // Report Balance after a Trade Finished + + // + // Collector ... + bool eaSaveTrades; // Save Trades + bool eaSaveSignals; // Save Signals + bool eaSaveWins; // Save Winning Conditions + bool eaSaveLosts; // Save Lost Conditions + bool eaSaveRestrictions; // Save Restriction Reports + + // + // GUI Management Panel ... + bool eaShowPanel; // Show Management Panel + double eaPanelAllowedTPSLStep; // Value for Change TP/SL in Each Step + double eaPanelMinAllowedRiskInPoint; // Min Allowed Risk in Point + double eaPanelRiskInPoint; // Risk in Point per Trades + double eaPanelRiskToRewardRatio; // Risk To Reward per Trades + double eaPanelVolume; // Default volume Per Trade + + // + // Requirements ... + + // + XCAlert *eaAlert; // EA Scope Alert Handler ... + XCGuard *eaGuard; // EA Scope Guard Handler ... + XCTrade *eaTrader; // EA Scope Trade Handler ... + XCVolume *eaVolume; // EA Scope Voluem Handler ... + XCTarget *eaTarget; // EA Scope Target Handler ... + XTimeTracker eaTimeTracker; // EA Scope Time Tracker ... + XCTradeManager *eaTradeManager; // EA Scope Trade Manager Handler ... + XCPositionDrawer *eaPositionDrawer; // EA Scope Position Drawer ... + + // + // Specified Event Handlers ... + TOnGuarded onGuardedEventHandler; + TCanAnalyse canAnalyseEventHandler; + TCheckForGuard checkForGuardEventHandler; + + // + // Tools / Actions / Handlers ... + + // + // Expert Advisor Event Handlers ... + + /** + * Handle Initialization of Expert ... + * + * @return ( bool ) + */ + bool HandleOnInit() + { + // + bool result = false; + + // + // Validate Inputs ... + result = ValidateInputs(); + if (!result) + { + return result; + } + + // + int count = 0; + bool has = false; + + // + // Initialize Alert Handler ... + eaAlert = new XCAlert(); + eaAlert.SetPrefix(eaLogSuffix); + eaAlert.SetLogAlerts(eaLogAlerts); + eaAlert.SetMailAlerts(eaMailAlerts); + eaAlert.SetPushAlerts(eaPushAlerts); + eaAlert.SetSaveAlerts(eaSaveAlerts); + eaAlert.SetEnableAlerts(eaEnableAlerts); + eaAlert.SetTerminalAlerts(eaTerminalAlerts); + + // + // Initialize Volume Manager ... + eaVolume = new XCVolume(); + result = eaVolume.Init( + eaVolumeSelect, + eaStaticVoluem, + eaDynamicVolumeStepBalance, + eaDynamicVolumeStepVolume, + eaConstantRiskBalance, + eaConstantPercent, + eaConstantBalance // + ); + if (!result) + { + return result; + } + + // + // Initialize Trader ... + eaTrader = new XCTrade( + eaSlippage, + eaMagicNumber, + 0, + 0, + eaMaxAllowedDrawdownFactor // + ); + + // + // Trade Handler Attachments ... + + // + // Position Modifiy Event Handlers ... + count = ArraySize(mOnModifyEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnModifyPositionEventHandler(mOnModifyEventHandlers[i]); + } + } + + // + // Position Stop Loss Event Handlers ... + count = ArraySize(mStopLossEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnStopLossEventHandler(mStopLossEventHandlers[i]); + } + } + + // + // Position Take Profit Event Handlers ... + count = ArraySize(mTakeProfitEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnTakeProfitEventHandler(mTakeProfitEventHandlers[i]); + } + } + + // + // Position Force Close Event Handlers ... + count = ArraySize(mOnForceCloseEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnForceClosePositionEventHandler(mOnForceCloseEventHandlers[i]); + } + } + + // + // Deals Changed Event Handlers ... + count = ArraySize(mDealsChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnDealsChangedEventHandler(mDealsChangedEventHandlers[i]); + } + } + + // + // Orders Changed Event Handlers ... + count = ArraySize(mOrdersChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnOrdersChangedEventHandler(mOrdersChangedEventHandlers[i]); + } + } + + // + // Positions Changed Event Handlers ... + count = ArraySize(mPositionsChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnPositionsChangedEventHandler(mPositionsChangedEventHandlers[i]); + } + } + + // + // Trade Changed Event Handlers ... + count = ArraySize(mTradeStateChangedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnTradeStateChangedEventHandler(mTradeStateChangedEventHandlers[i]); + } + } + + // + // Postion Partially Close Event Handlers ... + count = ArraySize(mOnPartialCloseEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnPartialClosePositionEventHandler(mOnPartialCloseEventHandlers[i]); + } + } + + // + // Signal Executed Event Handlers ... + count = ArraySize(mOnSignalExecutedEventHandlers); + has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + eaTrader.AddOnSignalExecutedEventHandler(mOnSignalExecutedEventHandlers[i]); + } + } + + // + // Initialize Guard Handler ... + eaGuard = new XCGuard( + eaAlert, + eaTrader // + ); + + // + // Attach Event Handler ... + eaGuard.onGuardEventListener = onGuardedEventHandler; + + // + // Initialize Target Handler ... + eaTarget = new XCTarget(eaTrader, eaAlert); + + // + // Init Position Drawer ... + eaPositionDrawer = new XCPositionDrawer(eaTrader); + + // + // Initialize Trae Manager ... + eaTradeManager = new XCTradeManager( + eaAlert, + eaTrader, + eaVolume, + eaGuard, + eaTarget // + ); + + // + // Configuring Trade Manager ... + + // + // Attache Check For Guard Event Listener ... + eaTradeManager.checkForGuardEventListener = checkForGuardEventHandler; + + // + eaTradeManager.SaveWins(eaSaveWins); + eaTradeManager.SaveLosts(eaSaveLosts); + eaTradeManager.SaveTrades(eaSaveTrades); + eaTradeManager.SaveSignals(eaSaveSignals); + eaTradeManager.SaveRestrictions(eaSaveRestrictions); + + // + // Setting Trade Reports ... + eaTradeManager + .SetTradeReports( + eaReportTrades, + eaReportSignals, + eaReportProtector, + eaReportRestrictions, + eaReportAfterTradesBalance // + ); + + // + // Setting Trade Permissions ... + eaTradeManager + .SetTradePermissions( + eaAllowTrade, + eaAllowLongs, + eaAllowShorts // + ); + + // + // Setting Symbol Configuration ... + XSymbolTradeConfig symbolConfigurations[]; + eaTradeManager.SetSymbolConfigurations(eaSymbolConfiguration); + count = eaTradeManager.FillSymbolConfigurations(symbolConfigurations); + has = IsValidSize(count); + if (has) + { + // + // Configure Signallers ... + for (int i = 0; i < count; i++) + { + // + // Register Signallers ... + PrepareSignallers(symbolConfigurations[i]); + } + } + SpecifiedClean(symbolConfigurations); + + // + result = InitPanel(); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Handle De Initialization of Expert ... + */ + void HandleOnDeInit() + { + // + DestroyPanel(); + + // + delete eaTrader; + ZeroMemory(eaTrader); + + // + delete eaGuard; + ZeroMemory(eaGuard); + + // + delete eaVolume; + ZeroMemory(eaVolume); + + // + eaTarget.Destroy(); + delete eaTarget; + ZeroMemory(eaTarget); + + // + delete eaTradeManager; + ZeroMemory(eaTradeManager); + + // + eaPositionDrawer.Destroy(); + delete eaPositionDrawer; + ZeroMemory(eaPositionDrawer); + + // + eaTimeTracker.Clean(); + + // + SpecifiedClean(eaSignallers); + SpecifiedClean(mOnSignalEventHandlers); + SpecifiedClean(mOnModifyEventHandlers); + SpecifiedClean(mStopLossEventHandlers); + SpecifiedClean(mTakeProfitEventHandlers); + SpecifiedClean(mOnForceCloseEventHandlers); + SpecifiedClean(mDealsChangedEventHandlers); + SpecifiedClean(mOrdersChangedEventHandlers); + SpecifiedClean(mOnPartialCloseEventHandlers); + SpecifiedClean(mPositionsChangedEventHandlers); + SpecifiedClean(mTradeStateChangedEventHandlers); + + // + string message = "DeInitialized Successfully ..."; + eaAlert.SendAlert(message); + + // + delete eaAlert; + ZeroMemory(eaAlert); + } + + /** + * Handle Tick ... + */ + void HandleOnTick() + { + // + // Update GUI Panel ... + UpdatePanel(); + + // + // Time Report ... + HandleTimeReport(); + + // + // Manage Trades ... + eaTradeManager.Manage(); + + // + // Manage Positions Drawings ... + eaPositionDrawer.Update(); + + // + int count = ArraySize(eaSignallers); + bool has = IsValidSize(count); + if (!has) + { + return; + } + + // + // Loop through Signallers ... + for (int i = 0; i < count; i++) + { + // + // Calling Process Ticks on Signaller ... + eaSignallers[i].OnTick(0); + } + + // + HandleOnTickAdditional(); + } + + /** + * Handle Trade ... + */ + void HandleOnTrade() + { + eaTrader.HandleOnTrade(); + } + + /** + * Handle Timer ... + */ + void virtual HandleOnTimer() + { + } + + /** + * Handle Chart Event ... + * + * @param id: int, Event id ... + * @param lparam: long, Event Long Parameter ... + * @param dparam: double, Event Double Parameter ... + * @param sparam: string, Event String Parameter ... + */ + void virtual HandleOnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // + ) + { + } + + // + // Event Triggered Listeners ... + + /** + * Handle New Signal Recieved ... + * + * @param signal: XSignal, Recieved Signal ... + */ + void HandleOnSignalTriggered(XSignal &signal) + { + eaTradeManager.HandleSignal(signal); + } + + /** + * Handle Signal Executed Event ... + * + * @param signal: XSignal, reference to Executed Signal ... + */ + void HandleOnSignalExecuted(XSignal &signal) + { + // + eaPositionDrawer.AddExecutedSignal(signal); + eaTradeManager.target.AddExecutedSignal(signal); + } + + /** + * Check For Guard ... + * + * @param guards: XGuard, reference Collection to holds result ... + * @param positions: XPosition, refrence collection to Provides Positions ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( int ) + */ + int CheckForGuardTriggered( + XGuard &guards[], + XPosition &positions[], + int barIndex = 0 // + ) + { + // + int result = 0; + + // + if (!HasChild(eaSignallers)) + { + return result; + } + + // + int count = ArraySize(eaSignallers); + for (int i = 0; i < count; i++) + { + // + XGuard iGuards[]; + int iGuardsCount = eaSignallers[i].CheckForGuard( + iGuards, + positions, + barIndex // + ); + if (IsValidSize(iGuardsCount)) + { + // + Copy( + iGuards, + guards, + false // + ); + } + + // + SpecifiedClean(iGuards); + } + + // + result = ArraySize(guards); + + // + return result; + } + + /** + * Handle Guard Events ... + * + * @param action: ENUM_X_GUARD_ACTIONS + * @param positions: XPosition[] + */ + void OnGuardedTriggered( + ENUM_X_GUARD_ACTIONS action, + XPosition &positions[] // + ) + { + eaTradeManager.HandleGuardEvent(action, positions); + } + + /** + * Check Can Analyse Market based on Time ... + * + * @param symbol: string, Specified Symbol ... + * @param period: ENUM_TIMEFRAMES, Specified Period ... + * @param time: datetime, Specified Time ... + * + * @return ( bool ) + */ + bool HandleCanAnalyseEventTriggered( + string symbol, + ENUM_TIMEFRAMES period, + datetime time // + ) + { + // + return eaTradeManager.CanAnalyse( + symbol, + period, + time // + ); + } + + // + // Trade Event Handlers ... + + /** + * Handle Stop Loss Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void virtual HandleOnStopLossTriggered(const XDeal &deal) + { + // + eaTradeManager.HandleSL(deal); + eaPositionDrawer.HandleStopLossTriggered(deal); + UpdatePanelPositionButtons(); + } + + /** + * Handle Take Profit Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void virtual HandleOnTakeProfitTriggered(const XDeal &deal) + { + // + UpdatePanelPositionButtons(); + eaTradeManager.HandleTP(deal); + eaPositionDrawer.HandleOnTakeProfitTriggered(deal); + } + + /** + * Handle Position Force Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param position: XPosition instance refrence, Triggered Position ... + * @param comment: string, Comment ... + */ + void virtual HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + // + UpdatePanelPositionButtons(); + eaTradeManager.HandleForceClose(position); + eaPositionDrawer.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); + } + + /** + * Handle Position Partially Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void virtual HandleOnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // + ) + { + // + eaTradeManager.HandlePartiallyClosed( + ticket, + profit, + comment // + ); + } + + /** + * Handle Deals Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void virtual HandleOnDealsChanged(int count) + { + } + + /** + * Handle Orders Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void virtual HandleOnOrdersChanged(int count) + { + } + + /** + * Handle Positions Changed ... + * + * @param count: int, number of changes ... + * if the count is positive, means new added ... + * if the count is negative, means removed ... + */ + void virtual HandleOnPositionsChanged(int count) + { + UpdatePanelPositionButtons(); + } + + /** + * Handle Position Modified Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void virtual HandleOnPositionModified( + const ulong ticket, + const double profit, + const string comment // + ) + { + // + eaPositionDrawer.HandleOnPositionModified( + ticket, + profit, + comment // + ); + } + + /** + * Handle all Trades States Changed Event ... + * + * @param state: XOnTradeHandlerState instance refrence, Changed Trade State data ... + */ + void virtual HandleOnTradeStateChanged(const XOnTradeHandlerState &state) + { + } + + // + // Validators ... + + /** + * Validate Inputs ... + * + * @return ( bool ) + */ + bool virtual ValidateInputs() + { + // + bool result = false; + + // + // TODO: Handle this ... + result = true; + + // + return result; + } + + // + // Viruals ... + + /** + * Prepare Signallers per Symbol Config ... + * + * @param symbolConfig: XSymbolTradeConfig, Symbol Trade Configurations ... + */ + void virtual PrepareSignallers(XSymbolTradeConfig &symbolConfig) + { + } + + /** + * Additional On Tick Processing if Required ... + * + * @param barIndex: int, Specified Bar Index ... + */ + void virtual HandleOnTickAdditional(int barIndex = 0) + { + } + + // + // Signal Event Handlers ... + + // + void AddOnSignalEventHandler(TOnSignal handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnSignalEventHandlers // + ); + } + + // + // Add New Signal Executed Event Handler ... + void AddOnSignalExecutedEventHandler(TOnSignal handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnSignalExecutedEventHandlers // + ); + } + + // + // Trade Event Handlers ... + + // + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mStopLossEventHandlers + // + ); + } + + // + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTakeProfitEventHandlers + // + ); + } + + // + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mDealsChangedEventHandlers + // + ); + } + + // + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOrdersChangedEventHandlers + // + ); + } + + // + void AddOnModifyPositionEventHandler(TOnModify handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnModifyEventHandlers + // + ); + } + + // + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mPositionsChangedEventHandlers + // + ); + } + + // + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTradeStateChangedEventHandlers + // + ); + } + + // + void AddOnForceClosePositionEventHandler(TOnForceClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnForceCloseEventHandlers + // + ); + } + + // + void AddOnPartialClosePositionEventHandler(TOnPartialClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnPartialCloseEventHandlers + // + ); + } + + // + // Protected ... + protected: + // + // Props ... + + // + // Actions and Tools ... + + /** + * Report Time Changes based on Given Configurations ... + */ + void HandleTimeReport() + { + // + if (eaAlert == NULL) + { + return; + } + + // + // Monthly Report .... + if (eaReportNewMonths && + eaTimeTracker.IsNewMonth()) + { + // + string msg = "New Month ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Weekly Report .... + if (eaReportNewWeeks && + eaTimeTracker.IsNewWeek()) + { + // + string msg = "New Week ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Daily Report .... + if (eaReportNewDays && + eaTimeTracker.IsNewDay()) + { + // + string msg = "New Day ..."; + + // + eaAlert.SendAlert(msg); + } + + // + // Hourly Report .... + if (eaReportNewHours && + eaTimeTracker.IsNewHour()) + { + // + string msg = "New Hour ..."; + + // + eaAlert.SendAlert(msg); + } + } + + /** + * Register Signaller ... + */ + void RegisterSignaller(XCBaseSignaller *signaller) + { + // + // Validate Signaller ... + if (signaller == NULL) + { + return; + } + + // + // Attach Signaller OnSignal Event Handlers if Exists ... + int count = ArraySize(mOnSignalEventHandlers); + bool has = IsValidSize(count); + if (has) + { + // + for (int i = 0; i < count; i++) + { + signaller.AddOnSignalEventHandler(mOnSignalEventHandlers[i]); + } + } + + // + // Attach Can Analyse Event Handler ... + signaller.canAnalyseEventListener = canAnalyseEventHandler; + + // + // Register Signaller ... + Add( + signaller, + eaSignallers // + ); + } + + // + // Private ... + private: + // + // Props ... + + // + // Specified Event Handlers ... + TOnModify mOnModifyEventHandlers[]; + TOnSignal mOnSignalEventHandlers[]; + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + TOnSignal mOnSignalExecutedEventHandlers[]; + TOnForceClose mOnForceCloseEventHandlers[]; + TOnDealsChanged mDealsChangedEventHandlers[]; + TOnOrdersChanged mOrdersChangedEventHandlers[]; + TOnPartialClose mOnPartialCloseEventHandlers[]; + TOnPositionsChanged mPositionsChangedEventHandlers[]; + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + XCBaseSignaller *eaSignallers[]; // All Registered Signallers ... + + // + // Panel Support ... + + // + XCChartHelper *eaChartHelper; // Chart Helper Class ... + + // + string objSuffix; + + // + CButton btnBuy; + CButton btnSell; + CButton btnClose; + CButton btnCloseAll; + CEdit lblPositionId; + + // + CButton lblTP; + CButton lblSL; + CButton btnSLPlus; + CButton btnTPPlus; + CButton btnSLMinus; + CButton btnTPMinus; + CButton btnSLPlusPlus; + CButton btnTPPlusPlus; + CButton btnSLMinusMinus; + CButton btnTPMinusMinus; + + // + CArrayObj posArray; + CButton *btnSelectedPosInfo; + CArrayObj selectedPosInfoArr; + + // + ulong selectedPositionID; + bool showSelectedPositionInfo; + + /** + * Initial Management GUI Panel ... + * + * @return ( bool ) + */ + bool InitPanel() + { + // + bool result = false; + + // + result = !eaShowPanel; + if (result) + { + return result; + } + + // + // Check Default Symbol and Period ... + + // + int subWindow = 0; + ulong chartId = ChartID(); + objSuffix = eaLogSuffix + "_"; + + // + // Initial Chart Class Instance ... + eaChartHelper = new XCChartHelper(chartId); + + // + int startX = 5; + int startY = 25; + + // + int defaultGap = 5; + int defaultWidth = 100; + int defaultHeight = 30; + + // + // Buy ... + int btnBuyX1 = startX; + int btnBuyX2 = startX + defaultWidth; + int btnBuyY1 = startY; + int btnBuyY2 = startY + defaultHeight; + string btnBuyName = objSuffix + "BTN_BUY"; + result = btnBuy.Create( + chartId, + btnBuyName, + subWindow, + btnBuyX1, + btnBuyY1, + btnBuyX2, + btnBuyY2 // + ); + if (result) + { + // + // Apply Buy Button Style ... + + // + btnBuy.Text("Buy"); + btnBuy.Color(clrYellow); + btnBuy.ColorBackground(clrGreen); + } + + // + // Sell ... + int btnSellX1 = btnBuyX1 + btnBuyX2; + int btnSellX2 = btnSellX1 + defaultWidth; + int btnSellY1 = btnBuyY1; + int btnSellY2 = btnBuyY2; + string btnSellName = objSuffix + "BTN_SELL"; + result = btnSell.Create( + chartId, + btnSellName, + subWindow, + btnSellX1, + btnSellY1, + btnSellX2, + btnSellY2 // + ); + if (result) + { + // + // Apply Sell Button Style ... + + // + btnSell.Text("Sell"); + btnSell.Color(clrYellow); + btnSell.ColorBackground(clrDarkRed); + } + + // + // LABEL Position ID ... + int lblPositionIdX1 = btnBuyX1; + int lblPositionIdX2 = lblPositionIdX1 + defaultWidth; + int lblPositionIdY1 = btnSellY2 + defaultGap; + int lblPositionIdY2 = lblPositionIdY1 + defaultHeight; + string lblPositionIdName = objSuffix + "LBL_POS_ID"; + result = lblPositionId.Create( + chartId, + lblPositionIdName, + subWindow, + lblPositionIdX1, + lblPositionIdY1, + lblPositionIdX2, + lblPositionIdY2 // + ); + if (result) + { + // + // Apply Label Position ID Style ... + lblPositionId.ReadOnly(true); + lblPositionId.Text("Pos ID: "); + lblPositionId.Color(clrYellow); + lblPositionId.ColorBackground(clrDarkGray); + } + + // + // Close ... + int btnCloseX1 = startX; + int btnCloseX2 = btnCloseX1 + defaultWidth; + int btnCloseY1 = lblPositionIdY2 + defaultGap; + int btnCloseY2 = btnCloseY1 + defaultHeight; + string btnCloseName = objSuffix + "BTN_CLOSE"; + result = btnClose.Create( + chartId, + btnCloseName, + subWindow, + btnCloseX1, + btnCloseY1, + btnCloseX2, + btnCloseY2 // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnClose.Text("Close"); + btnClose.Color(clrYellow); + btnClose.ColorBackground(clrDarkOrange); + } + + // + // Close All ... + int btnCloseAllX1 = btnCloseX2 + defaultGap; + int btnCloseAllX2 = btnCloseAllX1 + defaultWidth; + int btnCloseAllY1 = lblPositionIdY2 + defaultGap; + int btnCloseAllY2 = btnCloseAllY1 + defaultHeight; + string btnCloseAllName = objSuffix + "BTN_CLOSE_ALL"; + result = btnCloseAll.Create( + chartId, + btnCloseAllName, + subWindow, + btnCloseAllX1, + btnCloseAllY1, + btnCloseAllX2, + btnCloseAllY2 // + ); + if (result) + { + // + // Apply Close Button Style ... + + // + btnCloseAll.Text("Close All"); + btnCloseAll.Color(clrYellow); + btnCloseAll.ColorBackground(clrDarkRed); + } + + // + int minusPlusWidth = 20; + + // + // TP Label ... + int lblTPX1 = btnCloseX1; + int lblTPX2 = lblTPX1 + defaultWidth; + int lblTPY1 = btnCloseY2 + defaultGap; + int lblTPY2 = lblTPY1 + defaultHeight; + string lblTPName = objSuffix + "LBL_TP"; + result = lblTP.Create( + chartId, + lblTPName, + subWindow, + lblTPX1, + lblTPY1, + lblTPX2, + lblTPY2 // + ); + if (result) + { + // + // Apply Style ... + lblTP.Disable(); + lblTP.Text("TP"); + lblTP.Color(clrWhite); + lblTP.ColorBackground(clrGreen); + } + + // + // TP Plus ... + int btnTPPlusX1 = lblTPX1; + int btnTPPlusX2 = btnTPPlusX1 + minusPlusWidth; + int btnTPPlusY1 = lblTPY2 + defaultGap; + int btnTPPlusY2 = btnTPPlusY1 + defaultHeight; + string btnTPPlusName = objSuffix + "BTN_TP_PLUS"; + result = btnTPPlus.Create( + chartId, + btnTPPlusName, + subWindow, + btnTPPlusX1, + btnTPPlusY1, + btnTPPlusX2, + btnTPPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPPlus.Text("+"); + btnTPPlus.Color(clrYellow); + btnTPPlus.ColorBackground(clrGreen); + } + + // + // TP Plus Plus ... + int btnTPPlusPlusX1 = btnTPPlusX2 + defaultGap; + int btnTPPlusPlusX2 = btnTPPlusPlusX1 + minusPlusWidth; + int btnTPPlusPlusY1 = lblTPY2 + defaultGap; + int btnTPPlusPlusY2 = btnTPPlusPlusY1 + defaultHeight; + string btnTPPlusPlusName = objSuffix + "BTN_TP_PLUSPLUS"; + result = btnTPPlusPlus.Create( + chartId, + btnTPPlusPlusName, + subWindow, + btnTPPlusPlusX1, + btnTPPlusPlusY1, + btnTPPlusPlusX2, + btnTPPlusPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPPlusPlus.Text("++"); + btnTPPlusPlus.Color(clrYellow); + btnTPPlusPlus.ColorBackground(clrGreen); + } + + // + // TP Minus ... + int btnTPMinusX1 = lblTPX2 - minusPlusWidth; + int btnTPMinusX2 = btnTPMinusX1 + minusPlusWidth; + int btnTPMinusY1 = lblTPY2 + defaultGap; + int btnTPMinusY2 = btnTPMinusY1 + defaultHeight; + string btnTPMinusName = objSuffix + "BTN_TP_MINUS"; + result = btnTPMinus.Create( + chartId, + btnTPMinusName, + subWindow, + btnTPMinusX1, + btnTPMinusY1, + btnTPMinusX2, + btnTPMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPMinus.Text("-"); + btnTPMinus.Color(clrYellow); + btnTPMinus.ColorBackground(clrDarkRed); + } + + // + // TP Minus Minus ... + int btnTPMinusMinusX1 = btnTPMinusX1 - minusPlusWidth - defaultGap; + int btnTPMinusMinusX2 = btnTPMinusMinusX1 + minusPlusWidth; + int btnTPMinusMinusY1 = lblTPY2 + defaultGap; + int btnTPMinusMinusY2 = btnTPMinusY1 + defaultHeight; + string btnTPMinusMinusName = objSuffix + "BTN_TP_MINUSMINUS"; + result = btnTPMinusMinus.Create( + chartId, + btnTPMinusMinusName, + subWindow, + btnTPMinusMinusX1, + btnTPMinusMinusY1, + btnTPMinusMinusX2, + btnTPMinusMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnTPMinusMinus.Text("--"); + btnTPMinusMinus.Color(clrYellow); + btnTPMinusMinus.ColorBackground(clrDarkRed); + } + + // + // SL Label ... + int lblSLX1 = btnCloseAllX1; + int lblSLX2 = lblSLX1 + defaultWidth; + int lblSLY1 = btnCloseAllY2 + defaultGap; + int lblSLY2 = lblTPY1 + defaultHeight; + string lblSLName = objSuffix + "LBL_SL"; + result = lblSL.Create( + chartId, + lblSLName, + subWindow, + lblSLX1, + lblSLY1, + lblSLX2, + lblSLY2 // + ); + if (result) + { + // + // Apply Style ... + lblSL.Disable(); + lblSL.Text("SL"); + lblSL.Color(clrWhite); + lblSL.ColorBackground(clrDarkRed); + } + + // + // SL Plus ... + int btnSLPlusX1 = lblSLX1; + int btnSLPlusX2 = btnSLPlusX1 + minusPlusWidth; + int btnSLPlusY1 = lblSLY2 + defaultGap; + int btnSLPlusY2 = btnSLPlusY1 + defaultHeight; + string btnSLPlusName = objSuffix + "BTN_SL_PLUS"; + result = btnSLPlus.Create( + chartId, + btnSLPlusName, + subWindow, + btnSLPlusX1, + btnSLPlusY1, + btnSLPlusX2, + btnSLPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLPlus.Text("+"); + btnSLPlus.Color(clrYellow); + btnSLPlus.ColorBackground(clrGreen); + } + + // + // SL Plus Plus ... + int btnSLPlusPlusX1 = btnSLPlusX2 + defaultGap; + int btnSLPlusPlusX2 = btnSLPlusPlusX1 + minusPlusWidth; + int btnSLPlusPlusY1 = lblSLY2 + defaultGap; + int btnSLPlusPlusY2 = btnSLPlusPlusY1 + defaultHeight; + string btnSLPlusPlusName = objSuffix + "BTN_SL_PLUSPLUS"; + result = btnSLPlusPlus.Create( + chartId, + btnSLPlusPlusName, + subWindow, + btnSLPlusPlusX1, + btnSLPlusPlusY1, + btnSLPlusPlusX2, + btnSLPlusPlusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLPlusPlus.Text("++"); + btnSLPlusPlus.Color(clrYellow); + btnSLPlusPlus.ColorBackground(clrGreen); + } + + // + // SL Minus ... + int btnSLMinusX1 = lblSLX2 - minusPlusWidth; + int btnSLMinusX2 = btnSLMinusX1 + minusPlusWidth; + int btnSLMinusY1 = lblSLY2 + defaultGap; + int btnSLMinusY2 = btnSLMinusY1 + defaultHeight; + string btnSLMinusName = objSuffix + "BTN_SL_MINUS"; + result = btnSLMinus.Create( + chartId, + btnSLMinusName, + subWindow, + btnSLMinusX1, + btnSLMinusY1, + btnSLMinusX2, + btnSLMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLMinus.Text("-"); + btnSLMinus.Color(clrYellow); + btnSLMinus.ColorBackground(clrDarkRed); + } + + // + // SL Minus Minus ... + int btnSLMinusMinusX1 = btnSLMinusX1 - minusPlusWidth - defaultGap; + int btnSLMinusMinusX2 = btnSLMinusMinusX1 + minusPlusWidth; + int btnSLMinusMinusY1 = lblSLY2 + defaultGap; + int btnSLMinusMinusY2 = btnSLMinusY1 + defaultHeight; + string btnSLMinusMinusName = objSuffix + "BTN_SL_MINUSMINUS"; + result = btnSLMinusMinus.Create( + chartId, + btnSLMinusMinusName, + subWindow, + btnSLMinusMinusX1, + btnSLMinusMinusY1, + btnSLMinusMinusX2, + btnSLMinusMinusY2 // + ); + if (result) + { + // + // Apply Style ... + btnSLMinusMinus.Text("--"); + btnSLMinusMinus.Color(clrYellow); + btnSLMinusMinus.ColorBackground(clrDarkRed); + } + + // + UpdatePanelState(); + + // + return result; + } + + /** + * Listen For Panel Controls Events and + * Update State of GUI Panel ... + */ + void UpdatePanel() + { + // + if (!eaShowPanel) + { + return; + } + + // + UpdatePanelState(); + + // + // Buy Button Pressed ... + if (btnBuy.Pressed()) + { + // + HandleBuyTrade(); + btnBuy.Pressed(false); + } + + // + // Sell Button Pressed ... + if (btnSell.Pressed()) + { + // + HandleSellTrade(); + btnSell.Pressed(false); + } + + // + // Close Button Pressed ... + if (btnClose.Pressed()) + { + // + if (btnClose.IsEnabled()) + { + // + if (selectedPositionID > 0) + { + HandleCloseTrade(selectedPositionID); + } + } + + // + btnClose.Pressed(false); + } + + // + // Close All Button Pressed ... + if (btnCloseAll.Pressed()) + { + // + if (btnCloseAll.IsEnabled()) + { + HandleCloseTrade(0); + } + + // + btnCloseAll.Pressed(false); + } + + // + // Check Show Hide Selected Position Info ... + if (btnSelectedPosInfo != NULL) + { + // + if (btnSelectedPosInfo.Pressed()) + { + // + // Check Enable ... + if (btnSelectedPosInfo.IsEnabled()) + { + // + // Handle Toggle Show/Hide lblSelectedPositionInfo ... + CEdit *iLbl = NULL; + bool isVisible = showSelectedPositionInfo; + int count = selectedPosInfoArr.Total(); + if (IsValidSize(count)) + { + // + // Loop Through Labels ... + for (int i = 0; i < count; i++) + { + // + iLbl = (CEdit *)selectedPosInfoArr.At(i); + isVisible = iLbl.IsVisible(); + if (isVisible) + { + iLbl.Hide(); + } + else + { + iLbl.Show(); + } + } + + // + // Update Button Text ... + isVisible = showSelectedPositionInfo; + string btnText = isVisible + ? "Hide Info" + : "Show Info"; + btnSelectedPosInfo.Text(btnText); + showSelectedPositionInfo = !showSelectedPositionInfo; + } + + // + ZeroMemory(iLbl); + } + + // + btnSelectedPosInfo.Pressed(false); + } + } + + // + // TP Managing ... + + // + // TP Plus ... + if (btnTPPlus.Pressed()) + { + // + if (btnTPPlus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BULLISH); + } + + // + btnTPPlus.Pressed(false); + } + + // + // TP Plus Plus ... + if (btnTPPlusPlus.Pressed()) + { + // + if (btnTPPlusPlus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BULLISH, 2); + } + + // + btnTPPlusPlus.Pressed(false); + } + + // + // TP Minus ... + if (btnTPMinus.Pressed()) + { + // + if (btnTPMinus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BEARISH); + } + + // + btnTPMinus.Pressed(false); + } + + // + // TP Minus Minus ... + if (btnTPMinusMinus.Pressed()) + { + // + if (btnTPMinusMinus.IsEnabled()) + { + HandleTPChange(X_DIRECTION_BEARISH, 2); + } + + // + btnTPMinusMinus.Pressed(false); + } + + // + // SL Managing ... + + // + // SL Plus ... + if (btnSLPlus.Pressed()) + { + // + if (btnSLPlus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BULLISH); + } + + // + btnSLPlus.Pressed(false); + } + + // + // SL Plus Plus ... + if (btnSLPlusPlus.Pressed()) + { + // + if (btnSLPlusPlus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BULLISH, 2); + } + + // + btnSLPlusPlus.Pressed(false); + } + + // + // SL Minus ... + if (btnSLMinus.Pressed()) + { + // + if (btnSLMinus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BEARISH); + } + + // + btnSLMinus.Pressed(false); + } + + // + // SL Minus Minus ... + if (btnSLMinusMinus.Pressed()) + { + // + if (btnSLMinusMinus.IsEnabled()) + { + HandleSLChange(X_DIRECTION_BEARISH, 2); + } + + // + btnSLMinusMinus.Pressed(false); + } + + // + // Check Positions Buttons ... + int posCount = posArray.Total(); + bool has = IsValidSize(posCount); + if (has) + { + // + for (int i = 0; i < posCount; i++) + { + // + CButton *iBtn = (CButton *)posArray.At(i); + + // + if (iBtn.Pressed()) + { + // + if (iBtn.IsEnabled()) + { + // + ulong posID = ExtractPositionIDFromButtonName(iBtn.Name()); + if (posID > 0 && selectedPositionID != posID) + { + selectedPositionID = posID; + UpdatePanelState(); + } + } + + // + iBtn.Pressed(false); + } + + // + ZeroMemory(iBtn); + } + } + } + + /** + * Update GUI Panels Controls States ... + */ + void UpdatePanelState() + { + // + if (!eaShowPanel) + { + return; + } + // + // Update States Of Position Select Buttons ... + int count = posArray.Total(); + bool has = IsValidSize(count) && selectedPositionID > 0; + if (has) + { + // + for (int i = 0; i < count; i++) + { + // + CButton *iBtn = (CButton *)posArray.At(i); + + // + ulong posID = ExtractPositionIDFromButtonName(iBtn.Name()); + + // + // Select Position ... + XPosition iPos; + bool hasPosition = eaTrader.GetPosition( + posID, + iPos // + ); + string iTooltip = + !hasPosition + ? "" + : IsLong(iPos.type) + ? "Long" + : "Short"; + + // + if (posID == selectedPositionID) + { + // + iBtn.Disable(); + iBtn.ColorBackground(clrDarkGray); + } + else + { + // + iBtn.Enable(); + + // + color iBtnBG = IsLong(iPos.type) + ? clrGreen + : clrDarkRed; + + // + iBtn.ColorBackground(iBtnBG); + } + + // + ZeroMemory(iBtn); + } + } + + // + // Update State of Close All ... + if (has && count > 1) + { + // + btnCloseAll.Enable(); + btnCloseAll.ColorBackground(clrDarkRed); + } + else + { + // + btnCloseAll.Disable(); + btnCloseAll.ColorBackground(clrDarkGray); + } + + // + // Update Selected Position Info Button State ... + if (has) + { + // + // Reading Global Chart Info ... + int subWindow = 0; + int chartWidth = eaChartHelper.Width(); + ulong chartId = eaChartHelper.ChartId(); + + // + // Read Selected Position ... + XPosition selectedPosition; + bool hasPosition = eaTrader.GetPosition( + selectedPositionID, + selectedPosition // + ); + + // + // Read All Positions ... + double profits = 0; + XPosition positions[]; + string positionsInfo = ""; + int positionsCount = eaTrader.GetPositions(positions); + has = IsValidSize(positionsCount); + if (has) + { + // + for (int i = 0; i < positionsCount; i++) + { + profits += positions[i].profit; + } + + // + if (positionsCount > 1) + { + positionsInfo = "Positions Count: " + ToXString(positionsCount) + ", Profits: " + ToXString(profits); + } + } + + // + if (hasPosition) + { + // + // Preparing Position Info ... + string posTicket = "Ticket: " + ToXString(selectedPosition.ticket); + string posType = "Type: " + ToXString(selectedPosition.type); + string posSymbolPeriod = + "Symbol: " + selectedPosition.symbol + ", " + + "Period: " + ToXString(selectedPosition.period); + string posProfit = "Profit: " + ToXString(selectedPosition.profit); + string posRiskToRewardRatio = "RiskToReward: " + ToXString(selectedPosition.GetRiskRewardRatio()); + string accountInfo = + "Balance: " + ToXString(eaTrader.mAccount.GetBalance()) + ", " + + "Equity: " + ToXString(eaTrader.mAccount.GetEquity()); + + // + string posInfos[]; + + // + // Ticket ... + Add( + posTicket, + posInfos // + ); + + // + // Type ... + Add( + posType, + posInfos // + ); + + // + // Symbol Period ... + Add( + posSymbolPeriod, + posInfos // + ); + + // + // Profit ... + Add( + posProfit, + posInfos // + ); + + // + // Risk to Reward Ratio ... + Add( + posRiskToRewardRatio, + posInfos // + ); + + // + // Add Positions Info if Exists ... + if (IsSpecifiedValid(positionsInfo)) + { + // + Add( + positionsInfo, + posInfos // + ); + + // + // Clear Info Array ... + selectedPosInfoArr.Clear(); + } + + // + // Adding Account Info ... + Add( + accountInfo, + posInfos // + ); + + // + // Create Button If Not Exists ... + if (btnSelectedPosInfo == NULL) + { + // + btnSelectedPosInfo = new CButton(); + + // + string name = objSuffix + "BTN_TOOGLE_SPOS_INFO"; + + // + CRect iRect = btnTPPlus.Rect(); + + // + int x1 = iRect.left; + int x2 = x1 + 200 + 5; + + // + int y1 = iRect.bottom + 5; + int y2 = y1 + iRect.Height(); + + // + bool isCreated = btnSelectedPosInfo.Create( + chartId, + name, + subWindow, + x1, + y1, + x2, + y2 // + ); + if (!isCreated) + { + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + else + { + // + // Apply Styles ... + btnSelectedPosInfo.Color(clrYellow); + btnSelectedPosInfo.ColorBackground(clrDarkBlue); + } + } + + // + // Check Btn Exists ... + has = btnSelectedPosInfo != NULL; + if (has) + { + // + int posInfoCount = ArraySize(posInfos); + int lblInfoCount = selectedPosInfoArr.Total(); + has = IsValidSize(lblInfoCount) && lblInfoCount == posInfoCount; + + // + // Create info Labels ... + if (!has) + { + // + selectedPosInfoArr.Clear(); + has = IsValidSize(posInfoCount); + if (has) + { + // + // Creat Info Control ... + + // + string name = objSuffix + "LBL_SPOS_INFO"; + + // + int lblHeight = 25; + int lblWidth = 450; + + // + int startX = chartWidth - lblWidth - 5; + int sizeX = startX + lblWidth; + + // + int startY = 5; + int sizeY = startY + lblHeight; + + // + // Loop through Position Info's Array to Create Label Controls ... + for (int i = 0; i < posInfoCount; i++) + { + // + string iText = posInfos[i]; + string iTextMD5 = ToMD5(iText); + + // + string iName = name + "_" + iTextMD5; + + // + int iX1 = startX; + int iX2 = sizeX; + + // + int iY1 = startY; + int iY2 = startY + lblHeight; + + // + CEdit *iLbl = new CEdit(); + bool isCreated = iLbl.Create( + chartId, + iName, + subWindow, + iX1, + iY1, + iX2, + iY2 // + ); + if (isCreated) + { + // + iLbl.Text(iText); + iLbl.Color(clrYellow); + iLbl.ColorBorder(clrDarkSlateGray); + iLbl.ColorBackground(clrDarkSlateGray); + + // + if (showSelectedPositionInfo) + { + iLbl.Show(); + } + else + { + iLbl.Hide(); + } + + // + selectedPosInfoArr.Add(iLbl); + + // + startY = iY2; + } + } + } + } + + // + // Update Info Labels ... + lblInfoCount = selectedPosInfoArr.Total(); + has = IsValidSize(lblInfoCount); + if (has) + { + // + CEdit *iLbl = NULL; + + // + // Loop Through Infos ... + for (int i = 0; i < lblInfoCount; i++) + { + // + iLbl = (CEdit *)selectedPosInfoArr.At(i); + + // + iLbl.Text(posInfos[i]); + } + + // + bool isVisible = showSelectedPositionInfo; + string btnText = isVisible + ? "Hide Info" + : "Show Info"; + btnSelectedPosInfo.Text(btnText); + + // + ZeroMemory(iLbl); + } + } + + // + ZeroMemory(posInfos); + } + + // + SpecifiedClean(positions); + } + else + { + // + // Toggle Selected Position Btn ... + if (btnSelectedPosInfo != NULL) + { + // + btnSelectedPosInfo.Destroy(); + + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + + // + // Selected Position Lbls ... + selectedPosInfoArr.Clear(); + } + + // + // Update State of BtnClose and BtnClose All ... + if (selectedPositionID == 0) + { + // + btnClose.Disable(); + btnClose.ColorBackground(clrDarkGray); + + // + lblTP.Disable(); + lblTP.ColorBackground(clrDarkGray); + + // + btnTPPlus.Disable(); + btnTPPlus.ColorBackground(clrDarkGray); + + // + btnTPPlusPlus.Disable(); + btnTPPlusPlus.ColorBackground(clrDarkGray); + + // + btnTPMinus.Disable(); + btnTPMinus.ColorBackground(clrDarkGray); + + // + btnTPMinusMinus.Disable(); + btnTPMinusMinus.ColorBackground(clrDarkGray); + + // + lblSL.Disable(); + lblSL.ColorBackground(clrDarkGray); + + // + btnSLPlus.Disable(); + btnSLPlus.ColorBackground(clrDarkGray); + + // + btnSLPlusPlus.Disable(); + btnSLPlusPlus.ColorBackground(clrDarkGray); + + // + btnSLMinus.Disable(); + btnSLMinus.ColorBackground(clrDarkGray); + + // + btnSLMinusMinus.Disable(); + btnSLMinusMinus.ColorBackground(clrDarkGray); + } + else + { + // + btnClose.Enable(); + btnClose.ColorBackground(clrDarkOrange); + + // + lblTP.Enable(); + lblTP.ColorBackground(clrGreen); + + // + btnTPPlus.Enable(); + btnTPPlus.ColorBackground(clrGreen); + + // + btnTPPlusPlus.Enable(); + btnTPPlusPlus.ColorBackground(clrGreen); + + // + btnTPMinus.Enable(); + btnTPMinus.ColorBackground(clrDarkRed); + + // + btnTPMinusMinus.Enable(); + btnTPMinusMinus.ColorBackground(clrDarkRed); + + // + lblSL.Enable(); + lblSL.ColorBackground(clrDarkRed); + + // + btnSLPlus.Enable(); + btnSLPlus.ColorBackground(clrGreen); + + // + btnSLPlusPlus.Enable(); + btnSLPlusPlus.ColorBackground(clrGreen); + + // + btnSLMinus.Enable(); + btnSLMinus.ColorBackground(clrDarkRed); + + // + btnSLMinusMinus.Enable(); + btnSLMinusMinus.ColorBackground(clrDarkRed); + } + } + + /** + * Update Panel's Position Selector Buttons ... + */ + void UpdatePanelPositionButtons() + { + // + if (!eaShowPanel) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = eaTrader.GetPositions( + positions // + ); + bool has = IsValidSize(count); + if (!has) + { + // + posArray.Clear(); + selectedPositionID = 0; + UpdatePanelState(); + return; + } + + // + posArray.Clear(); + + // + // Selected Position ID ... + bool isSelectdPositionIDExists = false; + if (has && selectedPositionID > 0) + { + // + for (int i = 0; i < count; i++) + { + // + if (!isSelectdPositionIDExists && + positions[i].ticket == selectedPositionID) + { + // + isSelectdPositionIDExists = true; + break; + } + } + } + if (!isSelectdPositionIDExists || + selectedPositionID == 0) + { + // + XPosition youngest; + int youngestIDX = GetXYoungest(youngest, positions); + bool hasYoungest = IsValidIndex(youngestIDX) && + youngest.IsValid(); + if (hasYoungest) + { + selectedPositionID = youngest.ticket; + } + + // + youngest.Clean(); + } + + // + int subWindow = 0; + ulong chartId = eaChartHelper.ChartId(); + + // + int btnWidth = 25; + int btnHeight = 25; + + // + CRect iRect = lblPositionId.Rect(); + + // + int lastX = iRect.left + iRect.Width() + 5; + int lastSizeX = lastX + btnWidth; + + // + int lastY = iRect.top; + int lastSizeY = lastY + iRect.Height(); + + // + for (int i = 0; i < count; i++) + { + // + XPosition iPos = positions[i]; + + // + string posTypeStr = IsLong(iPos.type) + ? "LONG" + : "SHORT"; + + // + int iPosBtnX = lastX; + int iPosBtnSizeX = iPosBtnX + btnWidth; + string iPosBtnName = objSuffix + "_" + posTypeStr + "_POS_SELECT_BTN_" + ToXString(iPos.ticket); + + // + CButton *iPosBtn = new CButton(); + has = iPosBtn.Create( + chartId, + iPosBtnName, + subWindow, + iPosBtnX, + lastY, + iPosBtnSizeX, + lastSizeY // + ); + if (has) + { + // + // Apply Styles ... + string iPosBtnText = ToXString(iPos.ticket); + + // + iPosBtn.Text(iPosBtnText); + iPosBtn.Color(clrWhite); + + // + color iPosBtnBG = IsLong(iPos.type) + ? clrGreen + : clrDarkRed; + iPosBtn.ColorBackground(iPosBtnBG); + + // + lastX = iPosBtnSizeX + 5; + + // + if (selectedPositionID == iPos.ticket) + { + iPosBtn.Disable(); + } + + // + posArray.Add(iPosBtn); + } + + // + iPos.Clean(); + } + + // + ZeroMemory(positions); + UpdatePanelState(); + + // + } + + /** + * Destroy Management GUI Panel ... + */ + void DestroyPanel() + { + // + delete eaChartHelper; + ZeroMemory(eaChartHelper); + + // + delete btnSelectedPosInfo; + ZeroMemory(btnSelectedPosInfo); + } + + // + void NormalizePanelProps() + { + // + if (eaPanelVolume < 0.01) + { + eaPanelVolume = 0.01; + } + + // + if (eaPanelRiskInPoint < 0) + { + eaPanelRiskInPoint = 50; + } + + // + if (eaPanelAllowedTPSLStep < 5) + { + eaPanelAllowedTPSLStep = 5; + } + + // + if (eaPanelRiskToRewardRatio < 0.5) + { + eaPanelRiskToRewardRatio = 2; + } + + // + if (eaPanelMinAllowedRiskInPoint < 10) + { + eaPanelMinAllowedRiskInPoint = 10; + } + } + + // + ulong ExtractPositionIDFromButtonName(string name) + { + // + ulong result = 0; + + // + string nameParts[]; + int namePartsCount = SplitContent(nameParts, name, "_"); + bool has = IsValidSize(namePartsCount); + if (has) + { + // + string lastPart = nameParts[namePartsCount - 1]; + StringReplace(lastPart, "_", ""); + result = (long)lastPart; + } + + // + ZeroMemory(nameParts); + + // + return result; + } + + // + // Management Panel Event Handlers ... + + // + void HandleBuyTrade() + { + HandleTrade(X_DIRECTION_BULLISH); + } + + // + void HandleSellTrade() + { + HandleTrade(X_DIRECTION_BEARISH); + } + + // + void HandleTrade(ENUM_X_DIRECTION dir) + { + // + if (!HasDirection(dir)) + { + return; + } + + // + NormalizePanelProps(); + + // + bool isBullish = IsSpecifiedBullish(dir); + + // + double _volume = eaPanelVolume; + double r2r = eaPanelRiskToRewardRatio; + double _riskInPoints = eaPanelRiskInPoint; + double point = GetPoints(eaChartHelper.Symbol()); + double entry = GetEntry(eaChartHelper.Symbol(), dir); + + // + double risk = _riskInPoints * point; + double reward = risk * r2r; + + // + double sl = isBullish + ? entry - risk + : entry + risk; + double tp = isBullish + ? entry + reward + : entry - reward; + + // + string comment = eaLogSuffix + "_POS_" + ToXString(dir); + + // + if (isBullish) + { + // + eaTrader.Buy( + eaChartHelper.Symbol(), + eaChartHelper.Period(), + _volume, + entry, + sl, + tp, + comment // + ); + } + else + { + // + eaTrader.Sell( + eaChartHelper.Symbol(), + eaChartHelper.Period(), + _volume, + entry, + sl, + tp, + comment // + ); + } + } + + // + void HandleCloseTrade(ulong positionID) + { + // + if (positionID == 0) + { + // + XPosition positions[]; + int count = eaTrader.GetPositions( + positions // + ); + bool has = IsValidSize(count); + if (has) + { + // + int closedCount = eaTrader.Close(positions); + has = IsValidSize(closedCount); + } + } + else + { + // + XPosition position; + bool has = eaTrader.GetPosition( + positionID, + position // + ); + if (has) + { + // + has = eaTrader.Close(positionID); + } + } + } + + // + void HandleTPChange( + ENUM_X_DIRECTION dir, + int multiplier = 1 // + ) + { + // + // Validate ... + if (selectedPositionID == 0 || !HasDirection(dir)) + { + return; + } + + // + NormalizePanelProps(); + + // + // Normalize Multiplier ... + multiplier = NormalizeInt(multiplier, 1, 2); + + // + // Select Position ... + XPosition position; + bool has = eaTrader.GetPosition( + selectedPositionID, + position // + ); + if (!has) + { + // + position.Clean(); + return; + } + + // + bool isLong = IsLong(position.type); + bool isBullish = IsSpecifiedBullish(dir); + + // + double point = GetPoints(position.symbol); + double stepValue = multiplier * (point * eaPanelAllowedTPSLStep); + + // + bool mustIncrease = + isBullish + ? isLong + : !isLong; + + // + double tp = position.tp; + tp = + mustIncrease + ? tp + stepValue + : tp - stepValue; + bool isModified = eaTrader.Modify( + position.ticket, + position.sl, + tp, + objSuffix + "Change TP" // + ); + if (isModified) + { + UpdatePanelState(); + } + + // + position.Clean(); + } + + // + void HandleSLChange( + ENUM_X_DIRECTION dir, + int multiplier = 1 // + ) + { + // + // Validate ... + if (selectedPositionID == 0 || !HasDirection(dir)) + { + return; + } + + // + NormalizePanelProps(); + + // + // Normalize Multiplier ... + multiplier = NormalizeInt(multiplier, 1, 2); + + // + // Select Position ... + XPosition position; + bool has = eaTrader.GetPosition( + selectedPositionID, + position // + ); + if (!has) + { + // + position.Clean(); + return; + } + + // + bool isLong = IsLong(position.type); + bool isBullish = IsSpecifiedBullish(dir); + + // + double point = GetPoints(position.symbol); + double stepValue = multiplier * (point * eaPanelAllowedTPSLStep); + + // + bool mustIncrease = + isBullish + ? !isLong + : isLong; + + // + double risk = position.GetRiskInPoint(); + if (risk <= eaPanelMinAllowedRiskInPoint) + { + // + position.Clean(); + return; + } + + // + double sl = position.sl; + sl = + mustIncrease + ? sl + stepValue + : sl - stepValue; + bool isModified = eaTrader.Modify( + position.ticket, + sl, + position.tp, + objSuffix + "Change SL" // + ); + if (isModified) + { + UpdatePanelState(); + } + + // + position.Clean(); + } + + // +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-guard.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCXGuard ... +// Description: Guard Provider Class ... +// Ued in XCTradeManager ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm Guard Provider Class" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" +#include "../Libraries/x-saherelm.x-guard.lib.mq5" + +// +// Implementation ... +class XCGuard : public XCBase +{ + // + // public ... + public: + // + // Props ... + double minVolumeFactorForHedge; // Minimum Volume Factor for Hedge Profit Calculation ... + double minProfitPerVolumeFactorForHedge; // Minimum Required Profit per Volume Factor for Hedg ... + TOnGuarded onGuardEventListener; // On Guard Event Listener ... + + // + // Constructor(s) ... + XCGuard( + XCAlert *_alert, + XCTrade *_trader // + ) + { + // + alert = _alert; + trader = _trader; + + // + minVolumeFactorForHedge = 0.01; + minProfitPerVolumeFactorForHedge = 0.5; + } + + // + // Deconstructor(s) ... + ~XCGuard() + { + // + ZeroMemory(alert); + ZeroMemory(trader); + } + + // + // Tools ... + void DoGuards(XGuard &guards[]) + { + // + bool has = HasChild(guards); + if (!has) + { + return; + } + + // + XGuard tmp[]; + Copy( + guards, + tmp // + ); + while (HasChild(tmp)) + { + // + XGuard iGuard = tmp[0]; + ArrayRemove( + tmp, + 0, + 1 // + ); + + // + // Do Guard Action ... + DoGuard(iGuard); + } + + // + Clean(tmp); + } + + // + void DoGuard(XGuard &guard) + { + // + bool has = false; + + // + // Validate and Do Guard ... + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Switch Based on Guard Action ... + switch (guard.action) + { + // + // Close ... + case X_GUARD_ACTION_CLOSE: + DoClose(guard); + break; + + // + // Close All ... + case X_GUARD_ACTION_CLOSE_ALL: + DoCloseAll(guard); + break; + + // + // Close All Long Positions ... + case X_GUARD_ACTION_CLOSE_LONGS: + DoCloseLongs(guard); + break; + + // + // Close All Short Positions ... + case X_GUARD_ACTION_CLOSE_SHORTS: + DoCloseShorts(guard); + break; + + // + // Close In Losts ... + case X_GUARD_ACTION_CLOSE_IN_LOSTS: + DoCloseInLosts(guard); + break; + + // + // Close In Profits ... + case X_GUARD_ACTION_CLOSE_IN_PROFITS: + DoCloseInProfits(guard); + break; + + // + // Close In Lost Longs ... + case X_GUARD_ACTION_CLOSE_IN_LOST_LONGS: + DoCloseInLostLongs(guard); + break; + + // + // Close In Profit Longs ... + case X_GUARD_ACTION_CLOSE_IN_PROFIT_LONGS: + DoCloseInProfitLongs(guard); + break; + + // + // Close In Lost Shorts ... + case X_GUARD_ACTION_CLOSE_IN_LOST_SHORTS: + DoCloseInLostShorts(guard); + break; + + // + // Close In Profit Shorts ... + case X_GUARD_ACTION_CLOSE_IN_PROFITS_SHORT: + DoCloseInProfitShorts(guard); + break; + + // + // Partial Close ... + case X_GUARD_ACTION_PARTIAL_CLOSE: + DoPartialClose(guard); + break; + + // + // Trail Stop ... + case X_GUARD_ACTION_TRAIL_STOP: + DoTrailStop(guard); + break; + + // + // Trail Target ... + case X_GUARD_ACTION_TRAIL_TARGET: + DoTrailTarget(guard); + break; + + // + // Hedge Positions ... + case X_GUARD_ACTION_HEDGE: + DoHedge(guard); + break; + + // + } + } + + // + // protected ... + protected: + // + + // + bool GetPosition( + XPosition &position, + XGuard &guard // + ) + { + // + bool result = false; + + // + position.Clean(); + + // + result = + guard.IsValid() && + guard.ticket > 0; + if (!result) + { + return result; + } + + // + // Get Position ... + result = trader.GetPosition( + guard.ticket, + position // + ); + if (!result) + { + // + position.Clean(); + + // + return result; + } + + // + // Validate Position ... + result = + position.IsValid() && + position.symbol == guard.symbol && + position.provider == guard.provider && + position.period == guard.period; + if (!result) + { + // + position.Clean(); + + // + return result; + } + + // + return result; + } + + // + int GetPositions( + XPosition &positions[], + XGuard &guard // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = guard.IsValid(); + if (!has) + { + return result; + } + + // + result = trader.GetPositions( + positions, + guard.symbol, + guard.provider, + guard.period, + NULL, // All Types ... + true, // Filter By Magc ... + true // Force Clean ... + ); + + // + result = ArraySize(positions); + + // + return result; + } + + // + int GetLongPositions( + XPosition &positions[], + XGuard &guard // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = guard.IsValid(); + if (!has) + { + return result; + } + + // + result = trader.GetPositions( + positions, + guard.symbol, + guard.provider, + guard.period, + X_POSITION_TYPE_LONG, // Specified Types ... + true, // Filter By Magc ... + true // Force Clean ... + ); + + // + result = ArraySize(positions); + + // + return result; + } + + // + int GetShortPositions( + XPosition &positions[], + XGuard &guard // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = guard.IsValid(); + if (!has) + { + return result; + } + + // + result = trader.GetPositions( + positions, + guard.symbol, + guard.provider, + guard.period, + X_POSITION_TYPE_SHORT, // Specified Types ... + true, // Filter By Magc ... + true // Force Clean ... + ); + + // + result = ArraySize(positions); + + // + return result; + } + + // + int GetInProfitPositions( + XPosition &positions[], + XGuard &guard // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = guard.IsValid(); + if (!has) + { + return result; + } + + // + XPosition allPositions[]; + int allPositionsCount = GetPositions( + allPositions, + guard // + ); + has = IsValidSize(allPositionsCount); + if (!has) + { + return result; + } + + // + while (HasChild(allPositions)) + { + // + XPosition iPosition = allPositions[0]; + ArrayRemove( + allPositions, + 0, + 1 // + ); + + // + if (iPosition.profit > 0) + { + // + AddRef( + iPosition, + positions // + ); + } + + // + iPosition.Clean(); + } + Clean(allPositions); + + // + result = ArraySize(positions); + + // + return result; + } + + // + int GetInLostPositions( + XPosition &positions[], + XGuard &guard // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = guard.IsValid(); + if (!has) + { + return result; + } + + // + XPosition allPositions[]; + int allPositionsCount = GetPositions( + allPositions, + guard // + ); + has = IsValidSize(allPositionsCount); + if (!has) + { + return result; + } + + // + while (HasChild(allPositions)) + { + // + XPosition iPosition = allPositions[0]; + ArrayRemove( + allPositions, + 0, + 1 // + ); + + // + if (iPosition.profit < 0) + { + // + AddRef( + iPosition, + positions // + ); + } + + // + iPosition.Clean(); + } + Clean(allPositions); + + // + result = ArraySize(positions); + + // + return result; + } + + // + int GetInProfitLongPositions( + XPosition &positions[], + XGuard &guard // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = guard.IsValid(); + if (!has) + { + return result; + } + + // + XPosition allPositions[]; + int allPositionsCount = GetLongPositions( + allPositions, + guard // + ); + has = IsValidSize(allPositionsCount); + if (!has) + { + return result; + } + + // + while (HasChild(allPositions)) + { + // + XPosition iPosition = allPositions[0]; + ArrayRemove( + allPositions, + 0, + 1 // + ); + + // + if (iPosition.profit > 0) + { + // + AddRef( + iPosition, + positions // + ); + } + + // + iPosition.Clean(); + } + Clean(allPositions); + + // + result = ArraySize(positions); + + // + return result; + } + + // + int GetInLostLongPositions( + XPosition &positions[], + XGuard &guard // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = guard.IsValid(); + if (!has) + { + return result; + } + + // + XPosition allPositions[]; + int allPositionsCount = GetLongPositions( + allPositions, + guard // + ); + has = IsValidSize(allPositionsCount); + if (!has) + { + return result; + } + + // + while (HasChild(allPositions)) + { + // + XPosition iPosition = allPositions[0]; + ArrayRemove( + allPositions, + 0, + 1 // + ); + + // + if (iPosition.profit < 0) + { + // + AddRef( + iPosition, + positions // + ); + } + + // + iPosition.Clean(); + } + Clean(allPositions); + + // + result = ArraySize(positions); + + // + return result; + } + + // + int GetInProfitShortPositions( + XPosition &positions[], + XGuard &guard // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = guard.IsValid(); + if (!has) + { + return result; + } + + // + XPosition allPositions[]; + int allPositionsCount = GetShortPositions( + allPositions, + guard // + ); + has = IsValidSize(allPositionsCount); + if (!has) + { + return result; + } + + // + while (HasChild(allPositions)) + { + // + XPosition iPosition = allPositions[0]; + ArrayRemove( + allPositions, + 0, + 1 // + ); + + // + if (iPosition.profit > 0) + { + // + AddRef( + iPosition, + positions // + ); + } + + // + iPosition.Clean(); + } + Clean(allPositions); + + // + result = ArraySize(positions); + + // + return result; + } + + // + int GetInLostShortPositions( + XPosition &positions[], + XGuard &guard // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = guard.IsValid(); + if (!has) + { + return result; + } + + // + XPosition allPositions[]; + int allPositionsCount = GetShortPositions( + allPositions, + guard // + ); + has = IsValidSize(allPositionsCount); + if (!has) + { + return result; + } + + // + while (HasChild(allPositions)) + { + // + XPosition iPosition = allPositions[0]; + ArrayRemove( + allPositions, + 0, + 1 // + ); + + // + if (iPosition.profit < 0) + { + // + AddRef( + iPosition, + positions // + ); + } + + // + iPosition.Clean(); + } + Clean(allPositions); + + // + result = ArraySize(positions); + + // + return result; + } + + // + // Guard Handlers ... + + // + void DoClose(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + + // + // Validate Action and Requirements ... + has = + NotEmpty(guard.ticket) && + guard.action == X_GUARD_ACTION_CLOSE; + if (!has) + { + return; + } + + // + // Retrieve Position ... + XPosition position; + has = GetPosition( + position, + guard // + ); + if (!has) + { + // + position.Clean(); + + // + return; + } + + // + string comment = "Guard Close ..."; + + // + has = trader.Close( + position.ticket, + comment // + ); + if (has) + { + // + HandleNotifyPositionGuard(guard.action, position); + + // + string message = + "Guard Closed " + + ToXString(position.type) + + " Position (" + ToXString(position.ticket) + ") Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + position.Clean(); + } + + // + void DoCloseAll(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + has = guard.action == X_GUARD_ACTION_CLOSE_ALL; + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetPositions( + positions, + guard // + ); + has = IsValidSize(count); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Close All ..."; + + // + has = trader.Close( + positions, + comment // + ); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + string message = + "Guard Closed " + + ToXString(count) + + " Positions Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + void DoCloseInLosts(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + has = guard.action == X_GUARD_ACTION_CLOSE_IN_LOSTS; + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetInLostPositions( + positions, + guard // + ); + has = IsValidSize(count); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Close All In Losts ..."; + + // + has = trader.Close( + positions, + comment // + ); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + string message = + "Guard Closed " + + ToXString(count) + + " In Lost Positions Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + void DoCloseInProfits(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + has = guard.action == X_GUARD_ACTION_CLOSE_IN_PROFITS; + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetInProfitPositions( + positions, + guard // + ); + has = IsValidSize(count); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Close All In Profits ..."; + + // + has = trader.Close( + positions, + comment // + ); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + string message = + "Guard Closed " + + ToXString(count) + + " In Profit Positions Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + void DoCloseLongs(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + has = guard.action == X_GUARD_ACTION_CLOSE_LONGS; + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetLongPositions( + positions, + guard // + ); + has = IsValidSize(count); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Close Longs ..."; + + // + has = trader.Close( + positions, + comment // + ); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + string message = + "Guard Closed " + + ToXString(count) + + " Long Positions Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + void DoCloseInLostLongs(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + has = guard.action == X_GUARD_ACTION_CLOSE_IN_LOST_LONGS; + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetInLostLongPositions( + positions, + guard // + ); + has = IsValidSize(count); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Close All In Lost Longs ..."; + + // + has = trader.Close( + positions, + comment // + ); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + string message = + "Guard Closed " + + ToXString(count) + + " In Lost Longs Positions Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + void DoCloseInProfitLongs(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + has = guard.action == X_GUARD_ACTION_CLOSE_IN_PROFIT_LONGS; + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetInProfitLongPositions( + positions, + guard // + ); + has = IsValidSize(count); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Close All In Profit Longs ..."; + + // + has = trader.Close( + positions, + comment // + ); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + string message = + "Guard Closed " + + ToXString(count) + + " In Profit Longs Positions Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + void DoCloseShorts(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetShortPositions( + positions, + guard // + ); + has = IsValidSize(count); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Close Shorts ..."; + + // + has = trader.Close( + positions, + comment // + ); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + string message = + "Guard Closed " + + ToXString(count) + + " Long Positions Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + void DoCloseInLostShorts(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + has = guard.action == X_GUARD_ACTION_CLOSE_IN_LOST_SHORTS; + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetInLostShortPositions( + positions, + guard // + ); + has = IsValidSize(count); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Close All In Lost Shorts ..."; + + // + has = trader.Close( + positions, + comment // + ); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + string message = + "Guard Closed " + + ToXString(count) + + " In Lost Shorts Positions Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + void DoCloseInProfitShorts(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + has = guard.action == X_GUARD_ACTION_CLOSE_IN_PROFITS_SHORT; + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetInProfitShortPositions( + positions, + guard // + ); + has = IsValidSize(count); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Close All In Profit Shorts ..."; + + // + has = trader.Close( + positions, + comment // + ); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + // + string message = + "Guard Closed " + + ToXString(count) + + " In Profit Shorts Positions Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + void DoPartialClose(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + + // + // Validate Action and Requirements ... + has = + NotEmpty(guard.ticket) && + guard.volumeMultiplier > 0 && + guard.action == X_GUARD_ACTION_PARTIAL_CLOSE; + if (!has) + { + return; + } + + // + // Retrieve Position ... + XPosition position; + has = GetPosition( + position, + guard // + ); + if (!has) + { + // + position.Clean(); + + // + return; + } + + // + // Normalize Volume Multiplier ... + double vMult = guard.volumeMultiplier; + if (vMult > 0.5) + { + vMult = 0.5; + } + if (vMult < 0) + { + vMult = 0.5; + } + + // + // Calculate and Normalize Volume ... + double volume = position.volume * vMult; + volume = NormalizeVolume( + volume, + position.symbol // + ); + + // + string comment = "Guard Partially Closed: " + ToXString(volume) + " ..."; + + // + has = trader.ClosePartial( + position.ticket, + volume, + comment // + ); + if (has) + { + // + HandleNotifyPositionGuard(guard.action, position); + + // + string message = + "Guard Closed Partially " + + ToXString(volume) + " of " + + ToXString(position.type) + + " Position (" + ToXString(position.ticket) + ") Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + position.Clean(); + } + + // + void DoTrailStop(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + + // + // Validate Action and Requirements ... + has = + guard.sl >= 0 && + NotEmpty(guard.ticket) && + (guard.sl <= 0 + ? guard.force + : true) && + guard.action == X_GUARD_ACTION_TRAIL_STOP; + if (!has) + { + return; + } + + // + // Normalize SL ... + if (guard.sl < 0) + { + guard.sl = 0; + } + + // + // Retrieve Position ... + XPosition position; + has = GetPosition( + position, + guard // + ); + if (!has) + { + // + position.Clean(); + + // + return; + } + + // + bool isLong = IsLong(position.type); + bool isGuardPassed = + guard.sl > 0 + ? (isLong + ? position.price > guard.sl && + (position.sl == 0 || + position.sl < guard.sl) + : position.price < guard.sl && + (position.sl == 0 || + position.sl > guard.sl)) + : (guard.sl == 0 && guard.force); + + // + // Check Can Trail Stop or not ... + has = + // + // Position Exists ... + has && + // + // Positions in Profit for Trailling Stop ... + position.profit > 0 && + // + // Validate SL based on Position Type ... + isGuardPassed; + if (!has) + { + // + position.Clean(); + + // + return; + } + + // + string comment = "Guard Trail Stop ..."; + + // + has = trader.Modify( + position.ticket, + guard.sl, + position.tp, + comment // + ); + if (has) + { + // + HandleNotifyPositionGuard(guard.action, position); + + // + double before = NormalizePrice(position.sl, position.symbol); + double after = NormalizePrice(guard.sl, position.symbol); + + // + string message = + "Guard Trail Stop " + + ToXString(position.type) + + " Position (" + ToXString(position.ticket) + ")" + + " From: " + ToXString(before) + + "To: " + ToXString(after) + + " Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + position.Clean(); + } + + // + void DoTrailTarget(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + + // + // Validate Action and Requirements ... + has = + guard.tp >= 0 && + NotEmpty(guard.ticket) && + (guard.tp <= 0 + ? guard.force + : true) && + guard.action == X_GUARD_ACTION_TRAIL_TARGET; + if (!has) + { + return; + } + + // + // Normalize ... + if (guard.tp < 0) + { + guard.tp = 0; + } + + // + // Retrieve Position ... + XPosition position; + has = GetPosition( + position, + guard // + ); + if (!has) + { + // + position.Clean(); + + // + return; + } + + // + bool isLong = IsLong(position.type); + bool isGuardPassed = + guard.tp > 0 + ? (isLong + ? guard.tp > position.price + : guard.tp < position.price) + : (guard.tp == 0 && guard.force); + + // + // Check Can Trail Stop or not ... + has = + // + // Position Exists ... + has && + // + // Check TP is not Same ... + guard.tp != position.tp && + // + // Validate TP based on Current Price ... + isGuardPassed; + if (!has) + { + // + position.Clean(); + + // + return; + } + + // + string comment = "Guard Trail Target ..."; + + // + has = trader.Modify( + position.ticket, + position.sl, + guard.tp, + comment // + ); + if (has) + { + // + HandleNotifyPositionGuard(guard.action, position); + + // + double before = NormalizePrice(position.tp, position.symbol); + double after = NormalizePrice(guard.tp, position.symbol); + + // + string message = + "Guard Trail Target " + + ToXString(position.type) + + " Position (" + ToXString(position.ticket) + ")" + + " From: " + ToXString(before) + + "To: " + ToXString(after) + + " Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + position.Clean(); + } + + // + void DoHedge(XGuard &guard) + { + // + bool has = false; + + // + has = guard.IsValid(); + if (!has) + { + return; + } + + // + // Do What we want ... + + // + // Validate Action and Requirements ... + has = + (guard.force + ? true + : (minVolumeFactorForHedge > 0 && + minProfitPerVolumeFactorForHedge > 0)) && + guard.action == X_GUARD_ACTION_HEDGE; + if (!has) + { + return; + } + + // + // Retrieve Positions ... + XPosition positions[]; + int count = GetPositions( + positions, + guard // + ); + has = HasChild(positions); + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + // Calculate Positions Profits and Volumes ... + double swaps = 0; + double profits = 0; + double volumes = 0; + double commissions = 0; + for (int i = 0; i < count; i++) + { + // + swaps += positions[i].swap; + profits += positions[i].profit; + volumes += positions[i].volume; + commissions += positions[i].commission; + } + + // + // Check Profits and Volumes for Hedging ... + double hedgeValue = profits + (-1 * swaps) + commissions; + + // + // Check Force Hedging ... + if (!guard.force) + { + // + // Calculate Minimum Required Profit for Hedging ... + double minRequiredProfit = + (volumes / minVolumeFactorForHedge) * minProfitPerVolumeFactorForHedge; + + // + has = hedgeValue >= minRequiredProfit; + } + else + { + has = hedgeValue > 0; + } + + // + if (!has) + { + // + Clean(positions); + + // + return; + } + + // + string comment = "Guard Hedge ..."; + + // + // Loop through Positions and Close them One by One ... + // this is because of Trade Manager to Handle Close Trades ... + int closedCount = 0; + for (int i = 0; i < count; i++) + { + // + has = trader.Close( + positions[i].ticket, + comment // + ); + if (has) + { + closedCount++; + } + } + + // + has = IsValidSize(closedCount); + if (has) + { + // + HandleNotifyPositionsGuard(guard.action, positions); + + // + string message = + "Guard Hedge " + + ToXString(closedCount) + + " Positions by: " + + ToXString(hedgeValue) + + " Successfully ..."; + + // + alert.SendAlert(message); + } + + // + // Cleanup Resources ... + + // + Clean(positions); + } + + // + // private ... + private: + // + XCTrade *trader; + XCAlert *alert; + + // + void HandleNotifyPositionGuard( + ENUM_X_GUARD_ACTIONS action, + XPosition &position // + ) + { + // + if (!IsSpecifiedValid(action) || !position.IsValid() || onGuardEventListener == NULL) + { + return; + } + + // + XPosition positions[]; + AddRef( + position, + positions // + ); + HandleNotifyPositionsGuard(action, positions); + } + + // + void HandleNotifyPositionsGuard( + ENUM_X_GUARD_ACTIONS action, + XPosition &positions[] // + ) + { + // + if (!IsSpecifiedValid(action) || !HasChild(positions) || onGuardEventListener == NULL) + { + return; + } + + // + onGuardEventListener(action, positions); + } + + // +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-helper.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCBaseHelper +// Description: provides all Base Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Includes ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" + +// +// Definitions ... +enum ENUM_X_SCORE +{ + X_SCORE_NONE = 0, + X_SCORE_MIN = 1, + X_SCORE_NORMAL = 2, + X_SCORE_MAX = 3, +}; + +// #region Generics ... +// +// State Handler Generic Functions ... +#define DECLARE_STATE_FUNCTIONS(name, state_reader, bar_normalizer_func) \ + bool Is##name##Bullish(int barIndex = 0) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return state_reader(barIndex) >= 1; \ + } \ + bool Is##name##Bearish(int barIndex = 0) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return state_reader(barIndex) <= -1; \ + } \ + bool Is##name##SwitchedToBullish(int barIndex = 0) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return Is##name##Bullish(barIndex) && !Is##name##Bullish(barIndex + 1); \ + } \ + bool Is##name##SwitchedToBearish(int barIndex = 0) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return Is##name##Bearish(barIndex) && !Is##name##Bearish(barIndex + 1); \ + } + +// +// State Handler Based On Price Type Generic Functions ... +#define DECLARE_PRICE_BASED_STATE_FUNCTIONS(name, value_reader, bar_normalizer_func, point_reader_func, price_reader_func) \ + bool Is##name##Bullish(int barIndex = 0, ENUM_X_PRICE priceType = X_PRICE_CLOSE, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + double threshold = point_reader_func() * tolerance; \ + return price_reader_func(barIndex, priceType) > value_reader(barIndex) + threshold || \ + price_reader_func(barIndex, priceType) > value_reader(barIndex) - threshold; \ + } \ + bool Is##name##Bearish(int barIndex = 0, ENUM_X_PRICE priceType = X_PRICE_CLOSE, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + double threshold = point_reader_func() * tolerance; \ + return price_reader_func(barIndex, priceType) < value_reader(barIndex) + threshold || \ + price_reader_func(barIndex, priceType) < value_reader(barIndex) - threshold; \ + } \ + bool Is##name##SwitchedToBullish(int barIndex = 0, ENUM_X_PRICE priceType = X_PRICE_CLOSE, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return Is##name##Bullish(barIndex, priceType, tolerance) && !Is##name##Bullish(barIndex + 1, priceType, tolerance); \ + } \ + bool Is##name##SwitchedToBearish(int barIndex = 0, ENUM_X_PRICE priceType = X_PRICE_CLOSE, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return Is##name##Bearish(barIndex, priceType, tolerance) && !Is##name##Bearish(barIndex + 1, priceType, tolerance); \ + } + +// +// Value Comparator Generic Functions ... +#define DECLARE_VALUE_COMPARATOR_FUNCTIONS(name, value_reader, bar_normalizer_func, point_reader_func) \ + bool Is##name##OverLast(int barIndex = 0, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return IsOver( \ + value_reader(barIndex), \ + value_reader(barIndex + 1), \ + point_reader_func() * tolerance); \ + } \ + bool Is##name##UnderLast(int barIndex = 0, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return IsUnder( \ + value_reader(barIndex), \ + value_reader(barIndex + 1), \ + point_reader_func() * tolerance); \ + } \ + bool Is##name##SameAsLast(int barIndex = 0, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return IsSame( \ + value_reader(barIndex), \ + value_reader(barIndex + 1), \ + point_reader_func() * tolerance); \ + } \ + bool Is##name##CrossedOverLast(int barIndex = 0, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return Is##name##OverLast(barIndex, tolerance) && !Is##name##OverLast(barIndex + 1, tolerance); \ + } \ + bool Is##name##CrossedUnderLast(int barIndex = 0, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return Is##name##UnderLast(barIndex, tolerance) && !Is##name##UnderLast(barIndex + 1, tolerance); \ + } + +// +// Price Comparator Generic Functions ... +#define DECLARE_PRICE_COMPARATOR_FUNCTIONS(name, value_reader, bar_normalizer_func, price_reader_func) \ + bool IsPriceOver##name(int barIndex = 0, ENUM_X_PRICE priceType = X_PRICE_CLOSE) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return price_reader_func(barIndex, priceType) > value_reader(barIndex); \ + } \ + bool IsPriceUnder##name(int barIndex = 0, ENUM_X_PRICE priceType = X_PRICE_CLOSE) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return price_reader_func(barIndex, priceType) < value_reader(barIndex); \ + } \ + bool IsPriceCrossedOver##name(int barIndex = 0, ENUM_X_PRICE priceType = X_PRICE_CLOSE) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return IsPriceOver##name(barIndex, priceType) && !IsPriceOver##name(barIndex + 1, priceType); \ + } \ + bool IsPriceCrossedUnder##name(int barIndex = 0, ENUM_X_PRICE priceType = X_PRICE_CLOSE) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return IsPriceUnder##name(barIndex, priceType) && !IsPriceUnder##name(barIndex + 1, priceType); \ + } + +// +// Crossing Comparator Generic Functions ... +#define DECLARE_CROSSING_COMPARATOR_FUNCTIONS(baseName, fastName, slowName, fast_reader_func, slow_reader_func, bar_normalizer_func, point_reader_func) \ + bool Is##baseName##fastName##Over##Slow(int barIndex = 0, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + double fast = fast_reader_func(barIndex); \ + double slow = slow_reader_func(barIndex); \ + double distance = tolerance * point_reader_func(); \ + return fast > slow && MathAbs(fast - slow) >= distance; \ + } \ + bool Is##baseName##fastName##Under##Slow(int barIndex = 0, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + double fast = fast_reader_func(barIndex); \ + double slow = slow_reader_func(barIndex); \ + double distance = tolerance * point_reader_func(); \ + return fast < slow && MathAbs(fast - slow) >= distance; \ + } \ + bool Is##baseName##fastName##CrossedOver##Slow(int barIndex = 0, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return Is##baseName##fastName##Over##Slow(barIndex, tolerance) && !Is##baseName##fastName##Over##Slow(barIndex + 1, tolerance); \ + } \ + bool Is##baseName##fastName##CrossedUnder##Slow(int barIndex = 0, double tolerance = 2) \ + { \ + barIndex = bar_normalizer_func(barIndex); \ + return Is##baseName##fastName##Under##Slow(barIndex, tolerance) && !Is##baseName##fastName##Under##Slow(barIndex + 1, tolerance); \ + } +// #endregion + +// +// a Class for Handle base requirements ... +// for indicators ... +class XCBaseHelper : public XCBase +{ + // + // Public ... + public: + // + // Constructor ... + XCBaseHelper( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period // Trading Time Frame + ) + { + // + mSymbol = symbol; + mPeriod = period; + } + + // + // Deconstructor ... + ~XCBaseHelper() + { + // + IndicatorRelease(mHandler); + } + + // + // Setter(s) / Getter(s) ... + + // + // Symbol ... + string GetSymbol() + { + return mSymbol; + } + + // + // Period ... + ENUM_TIMEFRAMES GetPeriod() + { + return mPeriod; + } + + // + // Retrieve Bars ... + int CountBars() + { + // + int result = + Bars( + mSymbol, + mPeriod + // + ); + + // + return result; + } + + // + // Retrieve Indicator Calculated Bars ... + int CountCalculatedBars() + { + return BarsCalculated(mHandler); + } + + // + virtual void Free() + { + } + + // + // Generate Tag ... + virtual string GetTag() + { + // + string result = NULL; + + // + result = + // + GetToken() + + "[" + + GetSymbol() + "|" + + ToXString(GetPeriod()) + + "]" + // + ; + + // + return result; + } + + // + // Functions ... + + /** + * Validate Handler Exists ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = IsXValid(mSymbol) && + IsXValid(mPeriod) && + mHandler != INVALID_HANDLE; + + // + return result; + } + + /** + * Extract Validated Zones ... + * + * @param zones: XBoxZone, collection reference to holds results ... + * @param barIndex: int, Specified Bar Index ... + * @param requiredNumberOFZones: int, required Number of Zones ... + * @param breakValidLength: int, Breake Validation Length of Zones ... + * @param validateFakeBreakes: bool, Validation Fake Breaked Zones ... + * @param shadowMultiplier: double a Shadow Multiplier for Validation ... + * @param validationStrength: double, Minimum Strngth Multiplier in Point to Validate ... + * @param validationLength: int, Validation Length of Zones ... + * @param maxAllowedLoopbackLength: int, max Allowed Loopback Length ... + * + * @return ( int ) + */ + int ExtractBarZones( + XBoxZone &zones[], + int barIndex = 0, + int requiredNumberOFZones = 50, + int breakValidLength = 3, + bool validateFakeBreakes = true, + double shadowMultiplier = 3, + double validationStrength = 1, + int validationLength = 21, + int maxAllowedLoopbackLength = 1500 // + ) + { + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(zones); + + // + // Normalize ... + barIndex = NormalizeInt(barIndex, 0); + validationLength = NormalizeInt(validationLength, 7); + shadowMultiplier = NormalizeDouble(shadowMultiplier, 1); + validationStrength = NormalizeDouble(validationStrength, 1); + requiredNumberOFZones = NormalizeInt(requiredNumberOFZones, 5); + maxAllowedLoopbackLength = NormalizeInt(maxAllowedLoopbackLength, 100); + + // + // Reading Values ... + + // + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + double minAllowedStrength = (validationStrength * GetPoints(symbol)); + + // + XOHCL bar; + bool has = false; + + // + // Initialized Start Bar ... + has = bar.Init( + symbol, + period, + barIndex // + ); + if (!has) + { + return result; + } + + // + XOHCL iBar; + XBoxZone zone; + int start = barIndex; + bool isBullish = false; + bool isBearish = false; + bool lowShadowPassed = false; + bool highShadowPassed = false; + ENUM_X_DIRECTION dir = X_DIRECTION_NONE; + int end = start + maxAllowedLoopbackLength; + for (int i = start; i < end; i++) + { + // + // Cleanup ... + iBar.Clean(); + zone.Clean(); + dir = X_DIRECTION_NONE; + + // + // Reading HK Buffesr ... + has = bar.BarAt(i, iBar); + if (!has) + { + continue; + } + + // + // Check Direction ... + isBullish = iBar.open < iBar.close; + isBearish = iBar.open > iBar.close; + dir = + (isBullish && !isBearish) + ? X_DIRECTION_BULLISH + : (isBearish && !isBullish) + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + has = HasDirection(dir); + if (!has) + { + continue; + } + + // + // Low Shadow ... + lowShadowPassed = iBar.GetLowShadow() >= (shadowMultiplier * iBar.GetHighShadow()); + + // + // High Shadow ... + highShadowPassed = iBar.GetHighShadow() >= (shadowMultiplier * iBar.GetLowShadow()); + + // + has = (lowShadowPassed && !highShadowPassed) || + (highShadowPassed && !lowShadowPassed); + if (!has) + { + continue; + } + + // + // Filling Zone ... + + // + zone.symbol = symbol; + zone.period = period; + zone.from = GetBarTime( + zone.symbol, + zone.period, + i // + ); + zone.dir = lowShadowPassed + ? X_DIRECTION_BULLISH + : highShadowPassed + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + + // + zone.upper = + IsXBullish(zone.dir) + ? iBar.GetDown() + : IsXBearish(zone.dir) + ? iBar.high + : EMPTY_VALUE; + + // + zone.lower = + IsXBullish(zone.dir) + ? iBar.low + : IsXBearish(zone.dir) + ? iBar.GetUp() + : EMPTY_VALUE; + + // + zone.to = bar.time; + zone.type = "XBar_" + (IsXBullish(zone.dir) ? "Support" : IsXBearish(zone.dir) ? "Resistance" + : "") + + "_" + ToXString(TimeToSeconds(zone.from)); + + // + // Validate ... + has = + zone.IsValid() && + HasDirection(zone.dir) && + NotEmptyZero(zone.upper) && + NotEmptyZero(zone.lower) && + (zone.IsBullish() + ? bar.low > zone.upper + : bar.high < zone.lower) && + (zone.upper - zone.lower) >= minAllowedStrength && + ValidateBarZone(zone, validationLength, breakValidLength, validateFakeBreakes); + if (has) + { + // + AddIfNotExists( + zone, + zones // + ); + } + + // + // Cleanup Resources ... + zone.Clean(); + + // + // Validating ... + result = ArraySize(zones); + has = IsValidSize(result) && + result >= requiredNumberOFZones; + if (has) + { + break; + } + } + + // + // Cleanup Resources ... + bar.Clean(); + iBar.Clean(); + zone.Clean(); + + // + return result; + } + + /** + * Validate Bar Zone ... + * + * @param zone: XBoxZone, reference to Specified Zone ... + * @param validationLength: int, Validation Length of Zones ... + * @param breakValidLength: int, Break Validation Length of Zones ... + * @param validateFakeBreakes: bool, Validation Fake Breaked Zones ... + * + * @return ( bool ) + */ + bool ValidateBarZone( + XBoxZone &zone, + int validationLength = 1, + int breakValidLength = 3, + bool validateFakeBreakes = true // + ) + { + // + bool result = false; + + // + // Normalize ... + validationLength = NormalizeInt(validationLength, 1); + breakValidLength = NormalizeInt(breakValidLength, 2); + + // + // Validate ... + result = zone.IsValid(); + if (!result) + { + return result; + } + + // + // Requirements ... + XOHCL iBar; + int count = 0; + string symbol = GetSymbol(); + ENUM_TIMEFRAMES period = GetPeriod(); + + // + int start = zone.FromIndex() + 1; + int end = start + validationLength; + + // + // Validate Before ... + for (int i = start; i < end; i++) + { + // + // Initialize Indexed Bar ... + iBar.Clean(); + result = iBar.Init( + symbol, + period, + i // + ); + if (!result) + { + break; + } + + // + result = zone.IsBullish() + ? iBar.low > zone.lower + : iBar.high < zone.upper; + if (!result) + { + break; + } + } + + // + // Validating After ... + if (result) + { + // + start = zone.ToIndex() + 1; + count = zone.FromIndex() - start; + end = start + count; + for (int i = start; i < end; i++) + { + // + // Initialized Indexed Bar ... + iBar.Clean(); + result = iBar.Init( + symbol, + period, + i // + ); + if (!result) + { + break; + } + + // + result = zone.IsBullish() + ? iBar.low > zone.lower + : iBar.high < zone.upper; + if (!result) + { + // + // Check For Fake Breake ... + if (validateFakeBreakes && breakValidLength > 0) + { + // + result = i - 1 >= 0; + if (result) + { + // + for (int j = i - 1; j >= zone.ToIndex(); j--) + { + // + // Initialized Indexed Bar ... + iBar.Clean(); + result = iBar.Init( + symbol, + period, + j // + ); + if (!result) + { + break; + } + + // + result = zone.IsBullish() + ? iBar.close > zone.upper + : iBar.close < zone.lower; + if (result) + { + // + result = MathAbs(j - i) <= breakValidLength; + if (result) + { + break; + } + } + } + } + } + + // + if (!result) + { + break; + } + } + } + } + + // + // Cleanup Resource ... + iBar.Clean(); + + // + return result; + } + + /** + * Normalizing Bar Index ... + * + * @param barIndex: int, Provided Bar Index ... + * + * @return ( int ) + */ + int NormalizeBarIndex(int barIndex) + { + // + int result = barIndex; + + // + if (!IsValid()) + { + return result; + } + + // + int count = CountBars() - 1; + result = NormalizeInt(result, 0, count - 1); + + // + return result; + } + + // + // Protected ... + protected: + // + // Props ... + + // + // Symbol ... + string mSymbol; + + // + // Period ... + ENUM_TIMEFRAMES mPeriod; + + // + // Indicator Handler ... + int mHandler; + + /** + * Read Value of Specified Buffer ... + * + * @param bufferIndex: int, which handler buffer to read value ... + * @param barIndex: int, Specified Bar Index ... + * + * @return ( double ) + */ + double ReadValue( + int bufferIndex, + int barIndex = 0 // + ) + { + // + double result = EMPTY_VALUE; + + // + // Normalize ... + int barsTotal = CountBars(); + barIndex = NormalizeInt(barIndex, 0, barsTotal - 1); + bufferIndex = NormalizeInt(bufferIndex, 0); + + // + // Validate ... + if (!IsValid()) + { + return result; + } + + // + double tmp[]; + int count = CopyBuffer( + mHandler, + bufferIndex, + barIndex, + 1, + tmp // + ); + result = tmp[0]; + + // + return result; + } + + /** + * Read Values of Specified Buffer ... + * + * @param buffer: double, reference collection to holds result ... + * @param bufferIndex: int, which handler buffer to read value ... + * @param barIndex: int, Specified Bar Index ... + * @param count: int, number of items to read, 0 for WHOLE_ARRAY ... + * @param asSeries: bool, set As Series Buffer or not ... + * + * @return ( int ) + */ + int ReadValues( + double &buffer[], + int bufferIndex, + int barIndex = 0, + int count = 0, + bool asSeries = true // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(buffer); + + // + // Normalize ... + int barsTotal = CountBars(); + count = NormalizeInt(count, 0); + bufferIndex = NormalizeInt(bufferIndex, 0); + barIndex = NormalizeInt(barIndex, 0, barsTotal - 1); + + // + // Validate ... + if (!IsValid()) + { + return result; + } + + // + result = CopyBuffer( + mHandler, + bufferIndex, + barIndex, + count, + buffer // + ); + + // + // Set As Series Flag ... + ArraySetAsSeries(buffer, asSeries); + + // + result = ArraySize(buffer); + + // + return result; + } + + // + // Private ... + private: + // +}; + +// +// Tools .... + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-http.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCHttp +// Description: provides all HTTP requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Definitions ... + +// +enum X_HTTP_METHOD +{ + X_HTTP_GET, + X_HTTP_POST +}; + +// +// Imports ... + +// +// Includes ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// a Class for Manage Account ... +class XCHttp : public XCBase +{ + // + // Public ... + public: + // + // Constructor ... + XCHttp() + { + XCHttp("", 10000); + } + XCHttp( + string path, // Base Folder to Store Data + int timeout // base timeout for Requests + ) + { + // + Path(path); + Timeout(timeout); + } + + // + // Deconstructor ... + ~XCHttp() + { + } + + // + // Properties Getter(s) / Setter(s) ... + + // + // Path ... + void Path(string value) + { + // + mPath = value; + + // + if (!IsValid(mPath)) + { + mPath = GetTag(); + } + } + + string Path() + { + return mPath; + } + + // + // Timeout ... + void Timeout(int value) + { + mTimeout = value; + } + + // + int Timeout() + { + return mTimeout; + } + + // + // Error ... + int Error() + { + return mError; + } + + // + // Response ... + string Response() + { + return mResponse; + } + + // + // Overrides ... + string GetTag() override + { + return GetSpecificToken(this); + } + + // + // Tools ... + + // + // Send Global Request ... + int SendRequest( + X_HTTP_METHOD method, // Httm Request Method + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = -1; + + // + string strMethod = ToString(method); + if (StringLen(strMethod) == 0) + { + return result; + } + + // + // Reset State ... + ResetState(); + + // + result = WebRequest( + strMethod, + url, + headers, + timeout, + payload, + response, + responseHeaders); + + // + if (result < 0) + { + mError = GetLastError(); + } + else + { + mResponse = CharArrayToString(response); + } + + // + return result; + } + + // + // Get Request ... + int GetRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_GET, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Post Request ... + int PostRequest( + const string url, // Server Address + const string headers, // Headers providing + const char &payload[], // the Data which needs to Send + char &response[], // Response of request + string responseHeaders, // Response Headers + int timeout = 500 // Timeout for response default is 500 + ) + { + // + int result = SendRequest( + X_HTTP_POST, + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + return result; + } + + // + // Handle Download Specific URL Content to Specific Path and File Name ... + bool Download( + string url, // the URL address which going to download + string fileName // Specify Destination file name to Store Response + ) + { + // + bool result = false; + + // + string filePath = GetFilePath(fileName); + string cookie = NULL; + string referer = NULL; + int timeout = Timeout(); + + // + char payload[]; + string headers; + char response[]; + string responseHeaders; + + // + // Send Request ... + int requestResult = GetRequest( + url, + headers, + payload, + response, + responseHeaders, + timeout); + + // + // Define File Handler ... + int mFileHandler = FileOpen( + filePath, + FILE_WRITE | FILE_BIN); + if (mFileHandler == INVALID_HANDLE) + { + // + mError = GetLastError(); + return result; + } + + // + // Write Response to File ... + uint writed = FileWriteArray( + mFileHandler, + response, + 0, + ArraySize(response)); + FileFlush(mFileHandler); + FileClose(mFileHandler); + + // + result = writed > 0; + + // + return result; + } + + // + // END Provided Functions ... + // + + // + // Protected ... + protected: + // + // Destintion Folder Path ... + string mPath; + + // + // WEB Request Timeout Value ... + int mTimeout; + + // + // WEB Request's Response ... + string mResponse; + + // + // Error Value ... + int mError; + + // + // Private ... + private: + // + // Reset Errors State ... + void ResetState() + { + // + // Reset Errors ... + mError = -1; + mResponse = ""; + ResetLastError(); + } + + // + // Generate Full File Path ... + string GetFilePath(string fileName) + { + // + string result = ""; + + // + result = + // + Path() + "\\" + fileName + // + ; + + // + return result; + } +}; + +// +// Tools ... + +// +// Convert enum to String ... +string ToString(X_HTTP_METHOD method) +{ + // + string result = ""; + + // + switch (method) + { + // + case X_HTTP_GET: + result = "GET"; + break; + + // + case X_HTTP_POST: + result = "POST"; + break; + } + + // + return result; +} + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-market.pattern.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XCMarketPatternDetector +// Description: provides all Alerts requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-bar.analyser.class.mq5" +#include "../Libraries/x-saherelm.x-pivot.analysis.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.lib.mq5" + +// +// Definitions ... + +// +// Implementation ... +class XCMarketPatternDetector : public XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor ... + XCMarketPatternDetector() + { + barAnalyser = new XCBarAnalyser(); + } + + // + // Deconstructor ... + ~XCMarketPatternDetector() + { + // + delete barAnalyser; + ZeroMemory(barAnalyser); + } + + // + // Analysers ... + + /** + * Check for Price Touch Support Level ... + * + * @param bar: XOHCL, Specified Bar ... + * @param supportBar: XOHCL, reference to holds Zone Bar ... + * @param supportBox: XBoxZone, reference to holds Zone Box ... + * @param validationLength: int, Validation Length ... + * @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ... + * + * @return ( bool ) + */ + bool IsSupportTouched( + XOHCL &bar, + XOHCL &supportBar, + XBoxZone &supportBox, + int validationLength = 21, + int maxAllowedLoopback = 1500 // + ) + { + // + bool result = false; + + // + // Prepare ... + supportBar.Clean(); + supportBox.Clean(); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Check Support Exists ... + result = HasSupport( + bar, + supportBar, + validationLength, + maxAllowedLoopback // + ); + if (!result) + { + // + supportBar.Clean(); + return result; + } + + // + // Extract Support Box ... + result = ToSupportBox( + supportBar, + supportBox // + ); + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = + result && + bar.GetPreviousBar(pBar); + + // + // Chekc Price of Bar ... + result = + result && + pBar.low < supportBox.upper; + + // + // Cleanup Resources ... + if (!result) + { + // + supportBar.Clean(); + supportBox.Clean(); + } + pBar.Clean(); + + // + return result; + } + + /** + * Check for Price Touch Resistance Level ... + * + * @param bar: XOHCL, Specified Bar ... + * @param supportBar: XOHCL, reference to holds Zone Bar ... + * @param supportBox: XBoxZone, reference to holds Zone Box ... + * @param validationLength: int, Validation Length ... + * @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ... + * + * @return ( bool ) + */ + bool IsResistanceTouched( + XOHCL &bar, + XOHCL &resistanceBar, + XBoxZone &resistanceBox, + int validationLength = 21, + int maxAllowedLoopback = 1500 // + ) + { + // + bool result = false; + + // + // Prepare ... + resistanceBar.Clean(); + resistanceBox.Clean(); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Check Resistance Exists ... + result = HasResistance( + bar, + resistanceBar, + validationLength, + maxAllowedLoopback // + ); + if (!result) + { + // + resistanceBar.Clean(); + return result; + } + + // + // Extract Resistance Box ... + result = ToResistanceBox( + resistanceBar, + resistanceBox // + ); + + // + // Retrieve Previous Bar ... + XOHCL pBar; + result = + result && + bar.GetPreviousBar(pBar); + + // + // Chekc Price of Bar ... + result = + result && + pBar.high > resistanceBox.lower; + + // + // Cleanup Resources ... + if (!result) + { + // + resistanceBar.Clean(); + resistanceBox.Clean(); + } + pBar.Clean(); + + // + return result; + } + + /** + * Check a Bar has Same Sequence Directionalo Bar or Not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION, Detected Bars Direction ... + * @param count: int, Number of Same Bars ... + * @param validation: int, Validation of Same Bars ... + * @param loopback: int, Loopback for Detection ... + * + * @return ( bool ) + */ + bool HasSameBars( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int &count, + int validation = 3 // + ) + { + // + bool result = false; + + // + // Normalize ... + count = 0; + dir = X_DIRECTION_NONE; + + // + // Validate ... + result = + bar.IsValid() && + validation > 1; + if (!result) + { + return result; + } + + // + XOHCL tmpBar; + bar.GetPreviousBar(tmpBar); + while ((tmpBar.GetDirection() == bar.GetDirection()) || + ((bar.IsBullish() && !tmpBar.IsBearish()) || + (bar.IsBearish() && !tmpBar.IsBullish()))) + { + // + count++; + tmpBar.GetPreviousBar(tmpBar); + } + + // + // Validate Count ... + result = count >= validation; + if (result) + { + dir = bar.GetDirection(); + } + + // + result = + result && + count > 0 && + HasDirection(dir) && + count >= validation; + + // + tmpBar.Clean(); + + // + return result; + } + + /** + * Detect Confluence Statck based on Given Bar ... + * + * @param bar: XOHCL, Specified Bar for Start Detection ... + * @param zone: XBoxZone, confluence Zone, if exists ... + * @param forDir: ENUM_X_DIRECTION, Specified Required Zone Confluence ... + * @param retests: int, Number of Zone retesting ... + * @param loopback: int, Max allowed Loopback for Confluence Detection ... + * @param rangeLength: int, Loopback for Range Detecttion ... + * @param upperPriceType: ENUM_X_PRICE, zone upper Price Type ... + * @param lowerPriceType: ENUM_X_PRICE, + * @return ( bool ) + */ + bool HasConfluence( + XOHCL &bar, + XBoxZone &confluence, + ENUM_X_DIRECTION forDir, + int retests = 2, + int loopback = 15, + int rangeLength = 5, + ENUM_X_PRICE upperPriceType = X_PRICE_HIGH, + ENUM_X_PRICE lowerPriceType = X_PRICE_LOW // + ) + { + // + bool result = false; + + // + // Normalize ... + confluence.Clean(); + if (retests < 0) + { + retests = 0; + } + if (loopback < 2) + { + loopback = 2; + } + if (rangeLength < 2) + { + rangeLength = 2; + } + + // + // Validate ... + result = + bar.IsValid() && + HasDirection(forDir) && + IsXValid(upperPriceType) && + IsXValid(lowerPriceType); + if (!result) + { + return result; + } + + // + // Retrieve Upper and Lower ... + int mIndex = -1; + double upper = bar.FindHighest( + mIndex, + rangeLength, + upperPriceType // + ); + double lower = bar.FindLowest( + mIndex, + rangeLength, + lowerPriceType // + ); + + // + // Validate Upper/Lower ... + result = + NotEmptyZero(upper) && + NotEmptyZero(lower) && + upper > lower; + if (!result) + { + return result; + } + + // + // Validate Confluence ... + XOHCL tmpBar; + bool has = false; + int tmpCount = 0; + double tmpPrice = EMPTY_VALUE; + for (int i = bar.Index() + 1; i < bar.Index() + loopback; i++) + { + // + has = tmpBar.Init(bar.symbol, bar.period, i); + if (!has) + { + continue; + } + + // + tmpPrice = + IsXBullish(forDir) + ? tmpBar.GetPrice(upperPriceType) + : tmpBar.GetPrice(lowerPriceType); + has = + NotEmptyZero(tmpPrice) && + (IsXBullish(forDir) + ? tmpPrice < upper + : tmpPrice > lower); + if (!has) + { + // + tmpBar.Clean(); + + // + result = false; + break; + } + + // + // Counting retests ... + has = IsXBullish(forDir) + ? tmpPrice > lower + : tmpPrice > upper; + if (has) + { + tmpCount++; + } + + // + tmpBar.Clean(); + } + + // + // Validating Retests ... + if (result && retests > 0) + { + // + result = + result && + tmpCount >= retests; + } + + // + if (!result) + { + return result; + } + + // + result = confluence.Init( + bar.symbol, + bar.period, + upper, + lower, + GetBarTime(bar.symbol, bar.period, bar.Index() + loopback + 1), + bar.time, + forDir, + "XConfluence", + NULL // At ... + ); + + // + return result; + } + + // + // Detectors ... + + /** + * Check Specified Bar is Peak or Vale ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param validationLength: int, Validation Length ... + * + * @return ( bool ) + */ + bool IsPV( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int validationLength = 7, + ENUM_X_PRICE peakPriceType = X_PRICE_HIGH, // + ENUM_X_PRICE valePriceType = X_PRICE_LOW // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Normalize ... + validationLength = NormalizeInt(validationLength, 2); + + // + // Validate ... + result = bar.IsValid() && + IsXValid(peakPriceType) && + IsXValid(valePriceType); + if (!result) + { + return result; + } + + // + int valeIndex = -1; + double vale = bar.FindLowest( + valeIndex, + validationLength, + valePriceType // + ); + double barVale = bar.GetPrice(valePriceType); + bool isVale = + NotEmptyZero(vale) && + NotEmptyZero(barVale) && + IsValidIndex(valeIndex) && + vale >= barVale; + + // + int peakIndex = -1; + double peak = bar.FindHighest( + peakIndex, + validationLength, + peakPriceType // + ); + double barPeak = bar.GetPrice(peakPriceType); + bool isPeak = + NotEmptyZero(peak) && + NotEmptyZero(barPeak) && + IsValidIndex(peakIndex) && + peak <= barPeak; + + // + result = (isVale && !isPeak) || + (isPeak && !isVale); + if (result) + { + // + dir = + isVale + ? X_DIRECTION_BULLISH + : isPeak + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + // Get Result ... + result = HasDirection(dir); + + // + // Cleanup Resources ... + + // + return result; + } + + /** + * Check Specified Bar is Momentum Bar or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param requiredBars: int, bar range for approve Momentum ... + * @param approvedMultiplier: double, a Multipler for approve Momentum ... + * + * @return ( bool ) + */ + bool IsMomentumBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int requiredBars = 3, + double approvedMultiplier = 2 // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Normalizing ... + requiredBars = NormalizeInt(requiredBars, 3, 10); + approvedMultiplier = NormalizeDouble(approvedMultiplier, 2, 5); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Calculate Requirements ... + + // + XOHCL iBar; + bool has = false; + double rangeBody = 0; + int start = bar.Index() + 1; + int end = start + requiredBars; + for (int i = start; i < end; i++) + { + // + // Initialized Bar ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + + // + // Summarize Body Sizes ... + if (has) + { + rangeBody += iBar.GetBody(); + } + + // + iBar.Clean(); + } + + // + // Calculate Body Approvement ... + result = bar.GetBody() >= (approvedMultiplier * rangeBody); + if (!result) + { + return result; + } + + // + // Check Direction ... + dir = bar.GetDirection(); + + // + // Get Result ... + result = HasDirection(dir); + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar is Engulfed Bar or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * + * @return ( bool ) + */ + bool IsEngulfedBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Calculate Requirements ... + + // + XOHCL iBar; + result = bar.GetPreviousBar(iBar); + if (!result) + { + // + iBar.Clean(); + return result; + } + + // + // Check Prev Bar Must Inside Bar ... + result = bar.GetUp() > iBar.GetUp() && + bar.GetDown() < iBar.GetDown(); + if (!result) + { + // + iBar.Clean(); + return result; + } + + // + // Check Directions ... + bool isBullish = + iBar.IsBearish() && + bar.IsBullish(); + bool isBearish = + iBar.IsBullish() && + bar.IsBearish(); + result = isBullish || isBearish; + if (!result) + { + // + iBar.Clean(); + return result; + } + + // + dir = bar.GetDirection(); + + // + // Get Result ... + result = HasDirection(dir); + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar is True Gapped Bar or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param approvedPointMultiplier: double, Gap Validation Multiplier in Point ... + * + * @return ( bool ) + */ + bool IsTrueGapedBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + double approvedPointMultiplier = 1 // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Normalizing ... + approvedPointMultiplier = NormalizeDouble(approvedPointMultiplier, 1, 100); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Calculate Requirements ... + + // + XOHCL iBar; + result = bar.GetPreviousBar(iBar); + if (!result) + { + // + iBar.Clean(); + return result; + } + + // + // Check Directions ... + bool isBullish = + iBar.IsBullish() && + bar.IsBullish(); + bool isBearish = + iBar.IsBearish() && + bar.IsBearish(); + result = isBullish || isBearish; + if (!result) + { + // + iBar.Clean(); + return result; + } + + // + double point = GetPoints(bar.symbol); + double approvedGapSize = approvedPointMultiplier * point; + + // + // Check Gap Exists ... + result = + isBullish + ? bar.low > iBar.high + : iBar.low > bar.high; + if (!result) + { + // + iBar.Clean(); + return result; + } + + // + // Validate Gap Size ... + double gapSize = isBullish + ? bar.low - iBar.high + : iBar.low - bar.high; + result = gapSize >= approvedGapSize; + if (!result) + { + // + iBar.Clean(); + return result; + } + + // + dir = bar.GetDirection(); + + // + // Get Result ... + result = HasDirection(dir); + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar is Pinned Bar or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param shadowApprovedMultiplier: double, Shadow Size Approve Multiplier ... + * @param minimumPinBarRangeMultiplier: doubble, Range Size Approve Multiplier in Point ... + * @param forceDirection: bool, Apply Force Bar Type ... + * + * @return ( bool ) + */ + bool IsPinnedBar( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + double shadowApprovedMultiplier = 3, + double minimumPinBarRangeMultiplier = 4, + bool forceDirection = false // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Normalizing ... + shadowApprovedMultiplier = NormalizeDouble(shadowApprovedMultiplier, 2, 5); + minimumPinBarRangeMultiplier = NormalizeDouble(minimumPinBarRangeMultiplier, 2, 100); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Calculate Requirements ... + double body = bar.GetBody(); + double lowShadow = bar.GetLowShadow(); + double highShadow = bar.GetHighShadow(); + + // + // Check Directions ... + bool isBullish = + lowShadow > body && + lowShadow > highShadow && + lowShadow >= (body * shadowApprovedMultiplier); + bool isBearish = + highShadow > body && + highShadow > lowShadow && + highShadow > (body * shadowApprovedMultiplier); + result = isBullish || isBearish; + if (!result) + { + return result; + } + + // + // Checking Force Bar Type ... + if (forceDirection) + { + // + result = + isBullish + ? bar.IsBullish() + : bar.IsBearish(); + } + if (!result) + { + return result; + } + + // + // Check Range Validation ... + double point = GetPoints(bar.symbol); + double approvedRange = minimumPinBarRangeMultiplier * point; + result = bar.GetRange() >= approvedRange; + if (!result) + { + return result; + } + + // + // Setting Direction ... + dir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + result = HasDirection(dir); + + // + return result; + } + + /** + * Check Specified Bar has Star Pattern or not ... + * Morning Star => Bullish + * Evening Star => Bearish + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * + * @return ( bool ) + */ + bool IsStarPattern( + XOHCL &bar, + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Get Requirements ... + XOHCL pBar, p2Bar; + result = bar.GetPreviousBar(pBar); + result = result && + pBar.GetPreviousBar(p2Bar); + if (!result) + { + // + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + // Check Directions ... + bool isBullish = + bar.IsBullish() && + p2Bar.IsBearish(); + bool isBearish = + bar.IsBearish() && + p2Bar.IsBullish(); + result = isBullish || isBearish; + if (!result) + { + // + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + // Checking Gap Exists Between Bars ... + result = + isBullish + ? p2Bar.GetDown() > pBar.GetUp() && + pBar.GetUp() < bar.GetDown() + : p2Bar.GetUp() < pBar.GetDown() && + pBar.GetDown() > bar.GetUp(); + if (!result) + { + // + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + // Check Bar Close Validation ... + double barClosedApprovedPrice = p2Bar.GetDown() + ((p2Bar.GetUp() - p2Bar.GetDown()) / 2); + result = + isBullish + ? bar.close > barClosedApprovedPrice + : bar.close < barClosedApprovedPrice; + if (!result) + { + // + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + // Validating PBar Body and Shadow ... + double body = pBar.GetBody(); + double lowShadow = pBar.GetLowShadow(); + double highShadow = pBar.GetHighShadow(); + result = + body < bar.GetBody() && + body < p2Bar.GetBody() && + (isBullish + ? lowShadow > body && + lowShadow > highShadow + : highShadow > body && + highShadow > lowShadow); + if (!result) + { + // + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + // + dir = bar.GetDirection(); + + // + // Get Result ... + result = HasDirection(dir); + + // + // Cleanup Resources ... + pBar.Clean(); + p2Bar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar has Pirecing Pattern or not ... + * Piercing => Bullish + * Dark Cloud Cover => Bearish + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * + * @return ( bool ) + */ + bool IsPiercingPattern( + XOHCL &bar, + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + // Check Directions ... + bool isBullish = + bar.IsBullish() && + pBar.IsBearish(); + bool isBearish = + bar.IsBearish() && + pBar.IsBullish(); + result = isBullish || isBearish; + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + // Check Bar Close ... + double barCloseApprovedPrice = pBar.GetDown() + ((pBar.GetUp() - pBar.GetDown()) / 2); + result = + isBullish + ? bar.close > barCloseApprovedPrice + : bar.close < barCloseApprovedPrice; + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + dir = bar.GetDirection(); + + // + // Get Result ... + result = HasDirection(dir); + + // + // Cleanup Resources ... + pBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar has Rising Pattern or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * + * @return ( bool ) + */ + bool IsRisingPattern( + XOHCL &bar, + ENUM_X_DIRECTION &dir // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Reading Required Bars ... + XOHCL iBar; + XOHCL bars[]; + bool has = false; + int start = bar.Index(); + int end = start + 5; + for (int i = start; i < end; i++) + { + // + // Initialized Bar ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (has) + { + // + AddRef( + iBar, + bars // + ); + } + + // + iBar.Clean(); + } + result = ArraySize(bars) == 5; + if (!result) + { + // + iBar.Clean(); + SpecifiedClean(bars); + + // + return result; + } + + // + // Check Directions ... + bool isBullish = + bars[0].IsBullish() && + bars[4].IsBullish() && + bars[1].IsBearish() && + bars[2].IsBearish() && + bars[3].IsBearish(); + bool isBearish = + bars[0].IsBearish() && + bars[4].IsBearish() && + bars[1].IsBullish() && + bars[2].IsBullish() && + bars[3].IsBullish(); + result = isBullish || isBearish; + if (!result) + { + // + iBar.Clean(); + SpecifiedClean(bars); + + // + return result; + } + + // + // Check Range Validation ... + double upper = bars[4].GetUp(); + double lower = bars[4].GetDown(); + + // + double max = MathMax(bars[1].GetUp(), bars[2].GetUp()); + max = MathMax(max, bars[3].GetUp()); + + // + double min = MathMin(bars[1].GetDown(), bars[2].GetDown()); + min = MathMin(min, bars[3].GetDown()); + + // + result = + max < upper && + min > lower && + (isBullish + ? bars[0].close > bars[4].GetUp() + : bars[0].close < bars[4].GetDown()); + if (!result) + { + // + iBar.Clean(); + SpecifiedClean(bars); + + // + return result; + } + + // + dir = bar.GetDirection(); + + // + // Get Result ... + result = HasDirection(dir); + + // + // Cleanup Resources ... + iBar.Clean(); + SpecifiedClean(bars); + + // + return result; + } + + /** + * Check Specified Bar has Flag Pattern or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param swingBar: XOHCL, Detected Swing Bar ... + * @param minimumPullbackBars: int, Minimum Shoulders of Swing Bar ... + * + * @return ( bool ) + */ + bool IsFlagPattern( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + XOHCL &swingBar, + int minimumPullbackBars = 3 // + ) + { + // + bool result = false; + + // + // Prepare ... + swingBar.Clean(); + CleanDirection(dir); + + // + // Normalizing ... + minimumPullbackBars = NormalizeInt(minimumPullbackBars, 3, 10); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Reading Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + // Check Directions ... + bool isBullish = + bar.IsBullish() && + bar.close > pBar.GetUp(); + bool isBearish = + bar.IsBearish() && + bar.close < pBar.GetDown(); + result = isBullish || isBearish; + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + // Detect Swing Bar ... + ENUM_X_SWING_TYPE swingType = + isBullish + ? X_SWING_HIGH + : X_SWING_LOW; + result = + result && + IsXValid(swingType) && + bar.FindNextSwingBar( + swingType, + swingBar, + minimumPullbackBars // + ) && + (isBullish + ? swingBar.IsBullish() && + swingBar.high > pBar.high + : swingBar.IsBearish() && + swingBar.low < pBar.low); + if (!result) + { + // + pBar.Clean(); + swingBar.Clean(); + + // + return result; + } + + // + dir = bar.GetDirection(); + + // + // Get Result ... + result = HasDirection(dir); + + // + // Cleanup Resources ... + pBar.Clean(); + if (!result) + { + swingBar.Clean(); + } + + // + return result; + } + + /** + * Check Specified Bar has SignalKey Bar Pattern or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param shadowApprovedMultiplier: double, Shadow Size Approve Multiplier ... + * @param minimumPinBarRangeMultiplier: doubble, Range Size Approve Multiplier in Point ... + * @param forceDirection: bool, Apply Force Bar Type ... + * + * @return ( bool ) + */ + bool IsSignalKeyBarPattern( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + double shadowApprovedMultiplier = 3, + double minimumPinBarRangeMultiplier = 4, + bool forceDirection = false // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Get Requirements ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Chck Previous Bar must Pinned ... + result = IsPinnedBar( + pBar, + dir, + shadowApprovedMultiplier, + minimumPinBarRangeMultiplier, + forceDirection // + ); + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + // Check Direction ... + bool isBullish = + bar.IsBullish() && + IsSpecifiedBullish(dir) && + bar.close > pBar.high; + bool isBearish = + bar.IsBearish() && + IsSpecifiedBearish(dir) && + bar.close < pBar.low; + result = isBullish || isBearish; + if (!result) + { + // + pBar.Clean(); + return result; + } + + // + dir = bar.GetDirection(); + + // + result = HasDirection(dir); + + // + // Cleanup Resources ... + pBar.Clean(); + + // + return result; + } + + /** + * Check Specified Bar has Pullback Bar Pattern or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param zone: XBoxZone, refrence to hold detected zone ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param pullbackLength: int, min required indirectional bars to confirm pullback ... + * @param forceBreak: bool, force pullback bar breaks peak or vale of Zone ... + * + * @return ( bool ) + */ + bool IsPullbackPattern( + XOHCL &bar, + XBoxZone &zone, + ENUM_X_DIRECTION &dir, + int pullbackLength = 2, + bool forceBreak = false // + ) + { + // + bool result = false; + + // + // Prepare ... + zone.Clean(); + CleanDirection(dir); + + // + // Normalize ... + pullbackLength = NormalizeInt(pullbackLength, 2); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // First Bar Direction ... + dir = bar.GetDirection(); + result = HasDirection(dir); + if (!result) + { + return result; + } + + // + // Loop through Pullback Length ... + XOHCL iBar; + datetime from = NULL; + double max = EMPTY_VALUE; + double min = EMPTY_VALUE; + int start = bar.Index() + 1; + int end = start + pullbackLength; + for (int i = start; i < end; i++) + { + // + // Initialize Indexed Bar ... + iBar.Clean(); + result = bar.BarAt(i, iBar) && + iBar.GetDirection() == Opposit(dir); + if (!result) + { + break; + } + + // + // Calculate Max and Min ... + max = + !NotEmptyZero(max) + ? iBar.high + : MathMax(max, iBar.high); + min = + !NotEmptyZero(min) + ? iBar.low + : MathMin(min, iBar.low); + from = iBar.time; + } + + // + // Apply Force Break ... + if (result && + forceBreak) + { + // + result = + result && + NotEmptyZero(min) && + NotEmptyZero(max) && + (IsXBullish(dir) + ? bar.close > max + : bar.close < min); + } + + // + // Prepare Zone ... + if (result) + { + // + ToBox( + bar, + zone, + dir, + ToXString(X_BAR_PATTERN_PULLBACK) // + ); + zone.upper = max; + zone.lower = min; + zone.from = from; + zone.at = bar.time; + zone.to = bar.time; + + // + result = zone.IsValid(); + } + + // + // Cleanup ... + if (!result) + { + // + zone.Clean(); + CleanDirection(dir); + } + iBar.Clean(); + + // + return result; + } + + /** + * Check Market Has Consolidation Pattern or not ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param zone: XBoxZone, refrence to hold detected zone ... + * @param dir: ENUM_X_DIRECTION, reference to holds Detected Order Flow Direction ... + * @param validationLength: int, Validation Length ... + * @param breakPriceType: ENUM_X_PRICE, Specified Price Type to Breake Consolidation ... + * @param upperPriceType: ENUM_X_PRICE, Specified Price Type to Detected Upper of Consolidation ... + * @param lowerPriceType: ENUM_X_PRICE, Specified Price Type to Detected Lower of Consolidation ... + * + * @return ( bool ) + */ + bool IsConsolidationPattern( + XOHCL &bar, + XBoxZone &zone, + ENUM_X_DIRECTION &dir, + int validationLength = 5, + ENUM_X_PRICE breakPriceType = X_PRICE_CLOSE, + ENUM_X_PRICE upperPriceType = X_PRICE_HIGH, + ENUM_X_PRICE lowerPriceType = X_PRICE_LOW // + ) + { + // + // Descriptions: + // =============== + // Consolidation Zones Happens by Highest High and Lowest Low + // of Specified Range which Breakes From one Side ... + // + + // + bool result = false; + + // + // Prepare ... + zone.Clean(); + CleanDirection(dir); + + // + // Normalize ... + validationLength = NormalizeInt(validationLength, 3); + + // + // Validate ... + result = bar.IsValid() && + IsXValid(lowerPriceType) && + IsXValid(upperPriceType) && + IsXValid(breakPriceType); + if (!result) + { + return result; + } + + // + // Define Requirements ... + XOHCL iBar; + bool has = false; + datetime to = NULL; + datetime from = NULL; + double iLow = EMPTY_VALUE; + bool hasLowShadow = false; + double lower = EMPTY_VALUE; + double upper = EMPTY_VALUE; + double iHigh = EMPTY_VALUE; + bool hasHighShadow = false; + double iPrice = EMPTY_VALUE; + bool isLowerBreaked = false; + bool isUpperBreaked = false; + + // + // Loop Through Bars ... + int barIndex = bar.Index(); + int idx = barIndex; + bool canLookup = IsValidIndex(idx); + while (canLookup) + { + // + // Initialize Indexed Bar ... + idx++; + iBar.Clean(); + result = bar.BarAt(idx, iBar); + if (!result) + { + break; + } + + // + // Update Time ... + if (idx == barIndex + 1) + { + to = iBar.time; + } + + // + // Extract Low and High Price ... + iLow = iBar.GetPrice(lowerPriceType); + iHigh = iBar.GetPrice(upperPriceType); + result = NotEmptyZero(iLow) && + NotEmptyZero(iHigh); + if (!result) + { + break; + } + + // + // Check Bar Has Low/High Shadow ... + hasLowShadow = iBar.GetLowShadow() > iBar.GetHighShadow(); + hasHighShadow = iBar.GetHighShadow() > iBar.GetLowShadow(); + + // + // Update Range Lower and Upper based on Shadows ... + + // + // Lower ... + if (hasLowShadow) + { + // + // Check Can Update ... + has = + !NotEmptyZero(lower) + ? true + : iLow < lower; + if (has) + { + lower = iLow; + } + } + + // + // Upper ... + if (hasHighShadow) + { + // + // Check Can Update ... + has = + !NotEmptyZero(upper) + ? true + : iHigh > upper; + if (has) + { + upper = iHigh; + } + } + + // + // Check Price Breakes ... + iPrice = iBar.GetPrice(breakPriceType); + result = NotEmptyZero(iPrice); + if (!result) + { + break; + } + + // + // Check Upper/Lower breakes ... + isLowerBreaked = iPrice < lower; + isUpperBreaked = iPrice > upper; + + // + canLookup = (!isLowerBreaked && !isUpperBreaked); + if (!canLookup) + { + break; + } + + // + from = iBar.time; + } + + // + // Validate Calculations ... + result = + // + IsXValid(to) && + IsXValid(from) && + from < to && + // + NotEmptyZero(lower) && + NotEmptyZero(upper) && + upper > lower + // + ; + + // + // Validate To Edge Breakes ... + if (result) + { + // + iPrice = bar.GetPrice(breakPriceType); + result = NotEmptyZero(iPrice); + + // + // Validate To Edge Breakes ... + if (result) + { + // + isUpperBreaked = iPrice > upper; + isLowerBreaked = iPrice < lower; + + // + // Validate To Break ... + result = isUpperBreaked || isLowerBreaked; + } + + // + // Prepare Direction ... + if (result) + { + // + dir = + isUpperBreaked + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + } + + // + // Validate Direction ... + result = HasDirection(dir); + } + + // + // Prepare Zone ... + if (result) + { + // + zone.to = to; + zone.dir = dir; + zone.from = from; + zone.at = bar.time; + zone.upper = upper; + zone.lower = lower; + zone.symbol = bar.symbol; + zone.period = bar.period; + zone.type = ToXString(X_BAR_PATTERN_CONSOLIDATION); + + // + // Validate Zone ... + result = zone.IsValid(); + + // + // Validate Zone Length ... + if (result) + { + result = zone.FromIndex() - zone.ToIndex() >= validationLength; + } + } + + // + // Cleanup ... + if (!result) + { + // + zone.Clean(); + CleanDirection(dir); + } + iBar.Clean(); + + // + return result; + } + + bool HasCandlestickDirection( + XOHCL &bar, + ENUM_X_DIRECTION forDir, + bool checkStarPattern = true, + bool checkPinBarPattern = true, + bool checkPiercingPattern = true, + bool checkEngulfedPattern = true, + bool checkMomentumPattern = true, + bool checkSignalKeyBarPattern = true // + ) + { + // + bool result = false; + + // + // Validate ... + result = bar.IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + ENUM_X_DIRECTION tmpDir = X_DIRECTION_NONE; + + // + // Star ... + bool isStarPattern = false; + if (checkStarPattern) + { + // + isStarPattern = + IsStarPattern(bar, tmpDir) && + tmpDir == forDir; + } + + // + bool isPiercingPattern = false; + if (checkPiercingPattern) + { + // + isPiercingPattern = + IsPiercingPattern(bar, tmpDir) && + tmpDir == forDir; + } + + // + // Engulfed ... + bool isEngulfedPattern = false; + if (checkEngulfedPattern) + { + // + isEngulfedPattern = + IsEngulfedBar(bar, tmpDir) && + tmpDir == forDir; + } + + // + // PinBar ... + bool isPinBarPattern = true; + if (checkPinBarPattern) + { + // + isPinBarPattern = + IsPinnedBar(bar, tmpDir) && + tmpDir == forDir; + } + + // + // Signal Key Bar ... + bool isSignalKeyBarPattern = false; + if (checkSignalKeyBarPattern) + { + // + isSignalKeyBarPattern = + IsSignalKeyBarPattern(bar, tmpDir) && + tmpDir == forDir; + } + + // + // Momentum Bar ... + bool isMomentumBarPattern = false; + if (checkMomentumPattern) + { + // + isMomentumBarPattern = + IsMomentumBar(bar, tmpDir) && + tmpDir == forDir; + } + + // + result = + isStarPattern || + isPinBarPattern || + isPiercingPattern || + isEngulfedPattern || + isMomentumBarPattern || + isSignalKeyBarPattern; + + // + return result; + } + + /** + * Detect Order Flow ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param dir: ENUM_X_DIRECTION, reference to holds Detected Order Flow Direction ... + * @param orderFlow: XBoxZone, collection reference to holds Detected Order Flow ... + * @param orderFlowValidation: int, number of sequential Zones for Validate Order Flow ... + * @param containsOBs: bool, Specified to Use Order Blocks in Order Flow Detection ... + * @param containsFVGs: bool, Specified to Use Fair Value Gaps in Order Flow Detection ... + * @param containsSupportResistances: bool, Specified to Use Support and Resistances in Order Flow Detection ... + * @param zonesLoopback: int, Zone Detection Loopback ... + * @param zonesValidationLength: int, Zone Validation Length ... + * @param loopback: int, Max Allowed Loopback Bars for Collecting ... + * + * @return ( bool ) + */ + bool HasOrderFlow( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + XBoxZone &orderFlow[], + int orderFlowValidation = 2, + bool containsOBs = false, + bool containsFVGs = true, + bool containsSupportResistances = false, + int zonesLoopback = 5, + int zonesValidationLength = 21, + int loopback = 100 // + ) + { + // + bool result = false; + + // + // Prepare ... + XClean(orderFlow); + CleanDirection(dir); + int maxRequiredZone = 0; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 10); + zonesLoopback = NormalizeInt(zonesLoopback, 3); + maxRequiredZone = NormalizeInt(maxRequiredZone, 0); + orderFlowValidation = NormalizeInt(orderFlowValidation, 1); + zonesValidationLength = NormalizeInt(zonesValidationLength, 3); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Do ... + + // + // Collectiong Zones ... + XBoxZone tmp; + XBoxZone tmps[]; + XBoxZone _zones[]; + XBoxZone bullishZones[]; + XBoxZone bearishZones[]; + int bullishZonesCount = 0; + int bearishZonesCount = 0; + + // + // Order Blocks ... + if (containsOBs) + { + // + XClean(tmps); + CollectOBs(bar, tmps, zonesLoopback, maxRequiredZone, loopback); + FillNotExists(_zones, tmps); + } + + // + // Fair Value Gaps ... + if (containsFVGs) + { + // + XClean(tmps); + CollectFVGs(bar, tmps, zonesLoopback, maxRequiredZone, loopback); + FillNotExists(_zones, tmps); + } + + // + // Support and Resistances ... + if (containsSupportResistances) + { + // + XClean(tmps); + CollectZones(bar, tmps, zonesLoopback, maxRequiredZone, loopback); + FillNotExists(_zones, tmps); + } + + // + // Validate Zones ... + result = HasChild(_zones); + + // + // Extract Only Validated Zones ... + if (result) + { + // + ValidateBoxes( + _zones, + bar.Index() // Bars Length ... + ); + + // + UpdateToTime(_zones, bar.time); + RemoveBreakedZones(_zones, X_PRICE_CLOSE); + + // + result = HasChild(_zones); + } + + // + // Separate Zones Direction ... + if (result) + { + // + bullishZonesCount = ExtractByDirection(bullishZones, _zones, X_DIRECTION_BULLISH); + bearishZonesCount = ExtractByDirection(bearishZones, _zones, X_DIRECTION_BEARISH); + + // + result = IsValidSize(bullishZonesCount) || + IsValidSize(bearishZonesCount); + } + + // + // Looking for Sequences of Zones ... + if (result) + { + // + int idx = -1; + bool has = false; + XBoxZone bullOrderFlow[]; + XBoxZone bearOrderFlow[]; + + // + // Bullish OrderFlow ... + + // + // Sorting ... + Copy(bullishZones, bullOrderFlow); + Sort( + bullOrderFlow, + X_SORT_BY_DATE, + X_DIRECTION_BEARISH, + orderFlowValidation + 1 // + ); + bool hasBullishOrderFlow = ArraySize(bullOrderFlow) >= orderFlowValidation; + if (hasBullishOrderFlow) + { + // + // Validate Order Flow ... + Copy(bullOrderFlow, tmps); + XClean(bullOrderFlow); + while (HasChild(tmps)) + { + // + tmp.Clean(); + tmp = tmps[0]; + ArrayRemove(tmps, 0, 1); + + // + idx = GetHighest(tmps); + has = !IsValidIndex(idx) + ? true + : tmps[idx].lower < tmp.lower; + if (has) + { + AddIfNotExists(tmp, bullOrderFlow); + } + } + + // + hasBullishOrderFlow = ArraySize(bullOrderFlow) >= orderFlowValidation; + } + + // + // Bearish OrderFlow ... + + // + // Sorting ... + Copy(bearishZones, bearOrderFlow); + Sort( + bearOrderFlow, + X_SORT_BY_DATE, + X_DIRECTION_BULLISH, + orderFlowValidation + 1 // + ); + bool hasBearishOrderFlow = ArraySize(bearOrderFlow) >= orderFlowValidation; + if (hasBearishOrderFlow) + { + // + // Validate Order Flow ... + Copy(bearOrderFlow, tmps); + XClean(bearOrderFlow); + while (HasChild(tmps)) + { + // + tmp.Clean(); + tmp = tmps[0]; + ArrayRemove(tmps, 0, 1); + + // + idx = GetLowest(tmps); + has = !IsValidIndex(idx) + ? true + : tmps[idx].upper > tmp.upper; + if (has) + { + AddIfNotExists(tmp, bearOrderFlow); + } + } + + // + hasBearishOrderFlow = ArraySize(bearOrderFlow) >= orderFlowValidation; + } + + // + result = hasBullishOrderFlow || + hasBearishOrderFlow; + + // + // Validate Order Flows ... + if (result) + { + // + has = (hasBullishOrderFlow && !hasBearishOrderFlow) || + (hasBearishOrderFlow && !hasBullishOrderFlow); + + // + // When only Have One Direction ... + if (has) + { + // + if (hasBullishOrderFlow) + { + // + dir = X_DIRECTION_BULLISH; + Copy(bullOrderFlow, orderFlow); + } + else if (hasBearishOrderFlow) + { + // + dir = X_DIRECTION_BEARISH; + Copy(bearOrderFlow, orderFlow); + } + } + // + // When Two Direction Exists ... + else + { + // + // Retrieve Oldest Of Bullish / Bearish ... + int oldestBullIDX = GetOldest(bullOrderFlow); + int oldestBearIDX = GetOldest(bearOrderFlow); + result = IsValidIndex(oldestBullIDX) && + IsValidIndex(oldestBearIDX); + if (result) + { + // + dir = + bullOrderFlow[oldestBullIDX].from > bearOrderFlow[oldestBearIDX].from + ? X_DIRECTION_BULLISH + : bearOrderFlow[oldestBearIDX].from > bullOrderFlow[oldestBullIDX].from + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + result = HasDirection(dir); + if (result) + { + // + if (IsXBullish(dir)) + { + Copy(bullOrderFlow, orderFlow); + } + else if (IsXBearish(dir)) + { + Copy(bearOrderFlow, orderFlow); + } + } + } + } + + // + XClean(bullOrderFlow); + XClean(bearOrderFlow); + + // + result = HasChild(orderFlow) && + HasDirection(dir); + } + + // + // Validate Price ... + if (result) + { + // + int idx = -1; + if (IsXBullish(dir)) + { + // + idx = GetHighest(orderFlow); + result = IsValidIndex(idx) && + bar.low > orderFlow[idx].upper; + } + else + { + // + idx = GetLowest(orderFlow); + result = IsValidIndex(idx) && + bar.high < orderFlow[idx].lower; + } + } + + // + // Update To Time of Order Flow ... + if (result) + { + UpdateToTime(orderFlow, bar.time); + } + + // + // Cleanup ... + if (!result) + { + // + XClean(orderFlow); + CleanDirection(dir); + } + tmp.Clean(); + XClean(tmps); + XClean(_zones); + XClean(bullishZones); + XClean(bearishZones); + + // + return result; + } + + // + // FVG ... + + /** + * Check For FVG Exists in Specified Loopback Period ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param fvg: XBoxZone, reference for Holding FVG ... + * @param maxLoopback: int, Max Allowed Loopback to Lookup FVG ... + * + * @return ( bool ) + */ + bool HasFVG( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + XBoxZone &fvg, + int maxLoopback = 5 // + ) + { + // + bool result = false; + + // + // Prepare ... + fvg.Clean(); + CleanDirection(dir); + + // + // Normalize ... + maxLoopback = NormalizeInt(maxLoopback, 3); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL iBar; + bool has = false; + int start = bar.Index(); + int end = start + maxLoopback; + for (int i = start; i < end; i++) + { + // + // Initialize iBar ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!has) + { + continue; + } + + // + // Check iBar is FVG or not ... + has = barAnalyser.IsFVG( + iBar, + fvg, + true // Force Bar Type ... + ); + if (!has) + { + // + fvg.Clean(); + iBar.Clean(); + CleanDirection(dir); + + // + continue; + } + + // + iBar.Clean(); + dir = fvg.dir; + + // + break; + } + + // + // Check FVG Exists ... + result = fvg.IsValid(); + + // + // Check Direction Exists ... + result = + result && + HasDirection(dir); + + // + // Cleanup Resources ... + if (!result) + { + // + fvg.Clean(); + CleanDirection(dir); + } + iBar.Clean(); + + // + return result; + } + + // + // OB ... + + /** + * Check For OB Exists in Specified Loopback Period ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param ob: XBoxZone, reference for Holding OB ... + * @param maxLoopback: int, Max Allowed Loopback to Lookup OB ... + * + * @return ( bool ) + */ + bool HasOB( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + XBoxZone &ob, + int maxLoopback = 5 // + ) + { + // + bool result = false; + + // + // Prepare ... + ob.Clean(); + CleanDirection(dir); + + // + // Normalize ... + maxLoopback = NormalizeInt(maxLoopback, 3); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL iBar; + bool has = false; + int start = bar.Index(); + int end = start + maxLoopback; + for (int i = start; i < end; i++) + { + // + // Initialize iBar ... + has = iBar.Init( + bar.symbol, + bar.period, + i // + ); + if (!has) + { + continue; + } + + // + // Check iBar is OB or not ... + has = barAnalyser.IsOB( + iBar, + ob, + true, // Force FVG Bar Type ... + true // Force OB First Two Bar InDirection ... + ); + if (!has) + { + // + ob.Clean(); + iBar.Clean(); + CleanDirection(dir); + + // + continue; + } + + // + iBar.Clean(); + dir = ob.dir; + + // + break; + } + + // + // Check OB Exists ... + result = ob.IsValid(); + + // + // Check Direction Exists ... + result = + result && + HasDirection(dir); + + // + // Cleanup Resources ... + if (!result) + { + // + ob.Clean(); + CleanDirection(dir); + } + iBar.Clean(); + + // + return result; + } + + // + // Complex ... + + /** + * Check Double Pinned Bar ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param dir: ENUM_X_DIRECTION, reference to holds Pattern Direction ... + * @param shadowApprovedMultiplier: double, Shadow Size Approve Multiplier ... + * @param minimumPinBarRangeMultiplier: doubble, Range Size Approve Multiplier in Point ... + * @param forceDirection: bool, Apply Force Bar Type ... + * @param loopback: int, Max Allowed Detecting Loopback lenght ... + * + * @return ( bool ) + */ + bool IsDoublePinned( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + double shadowApprovedMultiplier = 3, + double minimumPinBarRangeMultiplier = 4, + bool forceDirection = false, + int loopback = 5 // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 1); + shadowApprovedMultiplier = NormalizeDouble(shadowApprovedMultiplier, 2, 5); + minimumPinBarRangeMultiplier = NormalizeDouble(minimumPinBarRangeMultiplier, 2, 100); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Do ... + + // + // Current Bar Must be a Pinned Bar ... + result = IsPinnedBar( + bar, + dir, + shadowApprovedMultiplier, + minimumPinBarRangeMultiplier, + forceDirection // + ); + if (!result) + { + // + CleanDirection(dir); + + // + return result; + } + + // + XOHCL iBar; + ENUM_X_DIRECTION iDir; + int start = bar.Index() + 1; + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + result = bar.BarAt(i, iBar); + result = result && IsPinnedBar( + iBar, + iDir, + shadowApprovedMultiplier, + minimumPinBarRangeMultiplier, + forceDirection // + ); + result = result && + iDir == dir; + if (result) + { + break; + } + } + + // + // Cleanup ... + if (!result) + { + CleanDirection(dir); + } + iBar.Clean(); + CleanDirection(iDir); + + // + return result; + } + + /** + * Check Double Engulfed Bar ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param dir: ENUM_X_DIRECTION, reference to holds Pattern Direction ... + * @param loopback: int, Max Allowed Detecting Loopback lenght ... + * + * @return ( bool ) + */ + bool IsDoubleEngulfed( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int loopback = 5 // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 1); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Do ... + + // + // Current Bar Must be a Pinned Bar ... + result = IsEngulfedBar( + bar, + dir // + ); + if (!result) + { + // + CleanDirection(dir); + + // + return result; + } + + // + XOHCL iBar; + ENUM_X_DIRECTION iDir; + int start = bar.Index() + 1; + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + result = bar.BarAt(i, iBar); + result = result && IsEngulfedBar( + iBar, + iDir // + ); + result = result && + iDir == dir; + if (result) + { + break; + } + } + + // + // Cleanup ... + if (!result) + { + CleanDirection(dir); + } + iBar.Clean(); + CleanDirection(iDir); + + // + return result; + } + + /** + * Check Double Momentum Bar ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param dir: ENUM_X_DIRECTION, reference to holds Pattern Direction ... + * @param requiredBars: int, bar range for approve Momentum ... + * @param approvedMultiplier: double, a Multipler for approve Momentum ... + * @param loopback: int, Max Allowed Detecting Loopback lenght ... + * + * @return ( bool ) + */ + bool IsDoubleMomentum( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + int requiredBars = 3, + double approvedMultiplier = 2, + int loopback = 5 // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 1); + requiredBars = NormalizeInt(requiredBars, 3, 10); + approvedMultiplier = NormalizeDouble(approvedMultiplier, 2, 5); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Do ... + + // + // Current Bar Must be a Pinned Bar ... + result = IsMomentumBar( + bar, + dir, + requiredBars, + approvedMultiplier // + ); + if (!result) + { + // + CleanDirection(dir); + + // + return result; + } + + // + XOHCL iBar; + ENUM_X_DIRECTION iDir; + int start = bar.Index() + 1; + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + result = bar.BarAt(i, iBar); + result = result && IsMomentumBar( + iBar, + iDir, + requiredBars, + approvedMultiplier // + ); + result = result && + iDir == dir; + if (result) + { + break; + } + } + + // + // Cleanup ... + if (!result) + { + CleanDirection(dir); + } + iBar.Clean(); + CleanDirection(iDir); + + // + return result; + } + + /** + * Check Has Double Patterns ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param dir: ENUM_X_DIRECTION, reference to holds Specified Patterns ... + * @param barPatterns: XPatternAnalysis, reference to Provides Bar's Pattern Analysis ... + * @param pBarPatterns: XPatternAnalysis, reference to Provides Previous Bar's Pattern Analysis ... + * @param allowedPatterns: ENUM_X_BAR_PATTERN, collection to Provide Allowed Bar Patterns for Detection ... + * @param config: XPatternAnalysisConfig, Provides Patterns Detection Config ... + * @param loopback: int, Max Allowed Loopback for Detection ... + * @param forDir: ENUM_X_DIRECTION, Specified Patterns Detection Direction ... + * + * @return ( bool ) + */ + bool HasDoublePatterns( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + XPatternAnalysis &barPatterns, + XPatternAnalysis &pBarPatterns, + ENUM_X_BAR_PATTERN &allowedPatterns[], + XPatternAnalysisConfig &config, + int loopback = 5, + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + // Prepare ... + barPatterns.Clean(); + CleanDirection(dir); + pBarPatterns.Clean(); + XPatternAnalysisConfig iConfig = config; + + // + // Normalize ... + loopback = NormalizeInt(loopback, 2); + + // + // Validate ... + result = bar.IsValid() && + HasChild(allowedPatterns); + if (!result) + { + return result; + } + + // + // Prepare Config ... + iConfig.CleanPatterns(); + if (HasChild(allowedPatterns)) + { + // + for (int i = 0; i < ArraySize(allowedPatterns); i++) + { + iConfig.AddPattern(allowedPatterns[i]); + } + } + + // + // Detect Bar Patterns ... + result = AnalyseBarPatterns(bar, barPatterns, config); + if (!result) + { + // + CleanDirection(dir); + barPatterns.Clean(); + pBarPatterns.Clean(); + + // + return result; + } + + // + // Check Direction ... + int bullishCount = barPatterns.Count(X_DIRECTION_BULLISH); + int bearishCount = barPatterns.Count(X_DIRECTION_BEARISH); + dir = + bullishCount > bearishCount + ? X_DIRECTION_BULLISH + : bearishCount > bullishCount + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + result = HasDirection(dir); + + // + // Check for Dir ... + if (HasDirection(forDir)) + { + // + result = + result && + dir == forDir; + } + + // + // Looping Back ... + if (result) + { + // + XOHCL iBar; + ENUM_X_DIRECTION iDir; + int start = bar.Index() + 1; + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + pBarPatterns.Clean(); + result = bar.BarAt(i, iBar); + result = result && + AnalyseBarPatterns(iBar, pBarPatterns, iConfig); + if (!result) + { + continue; + } + + // + bullishCount = pBarPatterns.Count(X_DIRECTION_BULLISH); + bearishCount = pBarPatterns.Count(X_DIRECTION_BEARISH); + iDir = + bullishCount > bearishCount + ? X_DIRECTION_BULLISH + : bearishCount > bullishCount + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + result = HasDirection(iDir); + result = result && + dir == iDir; + if (result) + { + break; + } + } + + // + iBar.Clean(); + CleanDirection(iDir); + } + + // + // Cleanup ... + if (!result) + { + // + CleanDirection(dir); + barPatterns.Clean(); + pBarPatterns.Clean(); + } + iConfig.Clean(); + + // + return result; + } + + /** + * Count Same Bars ... + * + * @param bar: XOHCL, Specified Bar ... + * @param sameBars: XOHCL, collection reference to holds same Bars ... + * @param dir: ENUM_X_DIRECTION, refrence to Founded Bars Direction holding ... + * @param forDir: ENUM_X_DIRECTION, Specified Looking Bar ... + * + * @return ( int ) + */ + int CountSameBars( + XOHCL &bar, + XOHCL &sameBars[], + ENUM_X_DIRECTION &dir, + ENUM_X_DIRECTION forDir // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(sameBars); + + // + // Validate ... + bool has = bar.IsValid(); + if (!has) + { + return result; + } + + // + XOHCL tmpBar; + ENUM_X_DIRECTION tmpDir = forDir; + int idx = bar.Index(); + while (has) + { + // + idx++; + tmpBar.Clean(); + has = bar.BarAt(idx, tmpBar); + if (has && !HasDirection(tmpDir)) + { + tmpDir = tmpBar.GetDirection(); + } + has = has && + tmpBar.GetDirection() == tmpDir; + if (!has) + { + break; + } + + // + AddIfNotExists(tmpBar, sameBars); + } + + // + result = ArraySize(sameBars); + if (IsValidSize(result)) + { + dir = tmpDir; + } + + // + // Cleanup ... + tmpBar.Clean(); + + // + return result; + } + + // + // Trending ... + + /** + * Check Trend Exists Based on Swings ... + * + * @param bar: XOHCL, Specified Bar ... + * @param dir: ENUM_X_DIRECTION a reference for Direction ... + * @param swings: XOHCL Array, Holds Swings ... + * @param numberOfSwings: int, Number of Swing Points for Detect Trend ... + * @param swingShoulders: int, Swing Shoulders Approvement Length ... + * + * @return ( bool ) + */ + bool HasSwingTrend( + XOHCL &bar, + ENUM_X_DIRECTION &dir, + XOHCL &swings[], + int numberOfSwings = 3, + int swingShoulders = 7 // + ) + { + // + bool result = false; + + // + // Prepare ... + CleanDirection(dir); + SpecifiedClean(swings); + + // + // Normalizing ... + numberOfSwings = NormalizeInt(numberOfSwings, 3, 10); + swingShoulders = NormalizeInt(swingShoulders, 3); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Check Trend Direction ... + XOHCL iSwing; + int idx = -1; + bool has = false; + XOHCL swingLows[]; + XOHCL swingHighs[]; + int lastSwingLowIndex = bar.Index(); + int lastSwingHighIndex = bar.Index(); + while (ArraySize(swingLows) < numberOfSwings || ArraySize(swingHighs) < numberOfSwings) + { + // + bool canLookupSwingLow = ArraySize(swingLows) < numberOfSwings; + bool canLookupSwingHigh = ArraySize(swingHighs) < numberOfSwings; + if (!canLookupSwingLow && !canLookupSwingHigh) + { + break; + } + + // + // Handle Swing Lows ... + if (canLookupSwingLow) + { + // + iSwing.Clean(); + idx = FindXSwing( + X_SWING_LOW, + bar.symbol, + bar.period, + lastSwingLowIndex + 1, + swingShoulders // + ); + has = IsValidIndex(idx); + if (has) + { + // + has = iSwing.Init( + bar.symbol, + bar.period, + idx // + ); + if (has) + { + // + AddRef( + iSwing, + swingLows // + ); + + // + lastSwingLowIndex = idx; + } + } + } + + // + // Handle Swing Highs ... + if (canLookupSwingHigh) + { + // + iSwing.Clean(); + idx = FindXSwing( + X_SWING_HIGH, + bar.symbol, + bar.period, + lastSwingHighIndex + 1, + swingShoulders // + ); + has = IsValidIndex(idx); + if (has) + { + // + has = iSwing.Init( + bar.symbol, + bar.period, + idx // + ); + if (has) + { + // + AddRef( + iSwing, + swingHighs // + ); + + // + lastSwingHighIndex = idx; + } + } + } + } + + // + // Check Trend Based On Swings ... + + // + // Check Directions ... + + // + bool isBullish = false; + bool isBearish = false; + + // + datetime oldestSwingLow = NULL; + datetime oldestSwingHigh = NULL; + + // + // Checking Bullish Trend based on Swing Lows ... + int count = ArraySize(swingLows); + for (int i = 0; i < count - 1; i++) + { + // + has = swingLows[i].low > swingLows[i + 1].low; + isBullish = + !isBullish + ? has + : isBullish && has; + if (!isBullish) + { + break; + } + + // + datetime oldeTime = MathMin(swingLows[i].time, swingLows[i + 1].time); + oldestSwingLow = + !IsSpecifiedValid(oldestSwingLow) + ? oldeTime + : MathMin(oldestSwingLow, oldeTime); + } + + // + // Checking Bearish Trend based on Swing Highs ... + count = ArraySize(swingHighs); + for (int i = 0; i < count - 1; i++) + { + // + has = swingHighs[i].high < swingHighs[i + 1].high; + isBearish = + !isBearish + ? has + : isBearish && has; + if (!isBearish) + { + break; + } + + // + datetime oldeTime = MathMin(swingHighs[i].time, swingHighs[i + 1].time); + oldestSwingHigh = + !IsSpecifiedValid(oldestSwingHigh) + ? oldeTime + : MathMin(oldestSwingHigh, oldeTime); + } + + // + result = isBullish || isBearish; + if (!result) + { + // + iSwing.Clean(); + SpecifiedClean(swingLows); + SpecifiedClean(swingHighs); + + // + return result; + } + + // + if (isBullish && + isBearish && + IsSpecifiedValid(oldestSwingLow) && + IsSpecifiedValid(oldestSwingHigh)) + { + // + // Here we Have to Detect Newest Trend or Oldest Trend ... + isBullish = oldestSwingLow < oldestSwingHigh; + isBearish = oldestSwingHigh < oldestSwingLow; + } + + // + result = (isBullish && !isBearish) || + (isBearish && !isBullish); + if (!result) + { + // + iSwing.Clean(); + SpecifiedClean(swingLows); + SpecifiedClean(swingHighs); + + // + return result; + } + + // + if (isBullish) + { + // + Copy( + swingLows, + swings // + ); + + // + dir = X_DIRECTION_BULLISH; + } + else + { + // + Copy( + swingHighs, + swings // + ); + + // + dir = X_DIRECTION_BEARISH; + } + + // + iSwing.Clean(); + SpecifiedClean(swingLows); + SpecifiedClean(swingHighs); + + // + return result; + } + + /** + * Check Specified Bar Has Support or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param support: XOHCL, Supported Bar ... + * @param validationLength: int, Validation Length ... + * @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ... + * + * @return ( bool ) + */ + bool HasSupport( + XOHCL &bar, + XOHCL &support, + int validationLength = 21, + int maxAllowedLoopback = 1500 // + ) + { + // + bool result = false; + + // + // Prepare ... + support.Clean(); + + // + // Normalizing ... + validationLength = NormalizeInt(validationLength, 7); + maxAllowedLoopback = NormalizeInt(maxAllowedLoopback, 21, 1500); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Find Support Swing ... + int idx = -1; + bool has = false; + int lookupIDX = bar.Index(); + while (!IsValidIndex(idx) && + lookupIDX < maxAllowedLoopback) + { + // + // Detect Swing ... + idx = FindXSwing( + X_SWING_LOW, + bar.symbol, + bar.period, + lookupIDX, + validationLength // + ); + has = IsValidIndex(idx); + if (!has) + { + // + lookupIDX++; + continue; + } + + // + // Retrieve Swing Bar ... + has = support.Init( + bar.symbol, + bar.period, + idx // + ); + if (!has) + { + // + idx = -1; + lookupIDX++; + support.Clean(); + continue; + } + + // + // Check Suppor Low Shadow ... + has = support.GetDown() < bar.low; + if (!has) + { + // + idx = -1; + lookupIDX++; + support.Clean(); + continue; + } + + // + if (IsValidIndex(idx)) + { + break; + } + } + + // + result = support.IsValid(); + + // + return result; + } + + /** + * Check Specified Bar Has Resistance or not ... + * + * @param bar: XOHCL, Specified Bar ... + * @param resistence: XOHCL, Resistanced Bar ... + * @param validationLength: int, Validation Length ... + * @param maxAllowedLoopback: int, Max Allowed Loopback to Detection ... + * + * @return ( bool ) + */ + bool HasResistance( + XOHCL &bar, + XOHCL &resistence, + int validationLength = 21, + int maxAllowedLoopback = 1500 // + ) + { + // + bool result = false; + + // + // Prepare ... + resistence.Clean(); + + // + // Normalizing ... + validationLength = NormalizeInt(validationLength, 7); + maxAllowedLoopback = NormalizeInt(maxAllowedLoopback, 21, 1500); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + // Find Support Swing ... + int idx = -1; + bool has = false; + int lookupIDX = bar.Index(); + while (!IsValidIndex(idx) && + lookupIDX < maxAllowedLoopback) + { + // + // Detect Swing ... + idx = FindXSwing( + X_SWING_HIGH, + bar.symbol, + bar.period, + lookupIDX, + validationLength // + ); + has = IsValidIndex(idx); + if (!has) + { + // + lookupIDX++; + continue; + } + + // + // Retrieve Swing Bar ... + has = resistence.Init( + bar.symbol, + bar.period, + idx // + ); + if (!has) + { + // + idx = -1; + lookupIDX++; + resistence.Clean(); + continue; + } + + // + // Check Resistance High Shadow ... + has = resistence.GetUp() > bar.high; + if (!has) + { + // + idx = -1; + lookupIDX++; + resistence.Clean(); + continue; + } + + // + if (IsValidIndex(idx)) + { + break; + } + } + + // + result = resistence.IsValid(); + + // + return result; + } + + /** + * Check Specified Bar Has Support or Resistance and Extract them ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param support: XBoxZone, reference to holds Detected Support ... + * @param resistance: XBoxZone, reference to holds Detected Resistance ... + * @param validationLength: int, Specified Validation Length ... + * @param loopback: int, Max Allowed Loopback Bars for Detection ... + * + * @return ( bool ) + */ + bool HasSupportResistance( + XOHCL &bar, + XBoxZone &support, + XBoxZone &resistance, + int validationLength = 7, + int loopback = 100 // + ) + { + // + bool result = false; + + // + // Prepare ... + support.Clean(); + resistance.Clean(); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 50); + validationLength = NormalizeInt(validationLength, 3); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL iZBar; + + // + // Support ... + iZBar.Clean(); + bool hasSupport = HasSupport( + bar, + iZBar, + validationLength, + loopback // + ); + if (hasSupport) + { + // + hasSupport = ToSupportBox( + iZBar, + support, + bar.time // + ); + } + + // + // Resistance ... + iZBar.Clean(); + bool hasResistance = HasResistance( + bar, + iZBar, + validationLength, + loopback // + ); + if (hasResistance) + { + // + hasResistance = ToResistanceBox( + iZBar, + resistance, + bar.time // + ); + } + + // + // Summarize Result ... + result = hasSupport || + hasResistance; + + // + // Cleanup ... + iZBar.Clean(); + + // + return result; + } + + // + // Analysers ... + + /** + * Analyse Specified Bar ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param analysis: XPatternAnalysis, reference to holds Analysis result ... + * @param config: XPatternAnalysisConfig, reference to Provides Detector Configs ... + * + * @return ( bool ) + */ + bool AnalyseBarPatterns( + XOHCL &bar, + XPatternAnalysis &analysis, + XPatternAnalysisConfig &config // + ) + { + // + bool result = false; + + // + // Prepare ... + analysis.Clean(); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + analysis.bar = bar; + analysis.time = TimeCurrent(); + + // + XOHCL iSwing; + XBoxZone iZone; + ENUM_X_DIRECTION iDir; + ENUM_X_BAR_PATTERN iPattern; + + // + bool has; + bool isBullish; + bool isBearish; + + // + bool canDetect; + bool canDetectBullish; + bool canDetectBearish; + + // + // Bars Detectors ... + + // + // XPV High Low Detection ... + canDetect = config.CanDetect(X_BAR_PATTERN_HIGH) || + config.CanDetect(X_BAR_PATTERN_LOW); + if (canDetect) + { + // + has = IsPV( + bar, + iDir, + config.pvValidationLength, + config.peakPriceType, + config.valePriceType // + ); + + // + canDetectBullish = config.CanDetect(X_BAR_PATTERN_LOW); + canDetectBearish = config.CanDetect(X_BAR_PATTERN_HIGH); + + // + isBullish = + has && + IsXBullish(iDir) && + canDetectBullish; + + // + isBearish = + has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + iPattern = + isBearish + ? X_BAR_PATTERN_HIGH + : X_BAR_PATTERN_LOW; + + // + analysis.AddPattern( + iPattern, + iDir // + ); + } + } + + // + // Momentum ... + iPattern = X_BAR_PATTERN_MOMENTUM; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = IsMomentumBar( + bar, + iDir, + config.momentumBarValidationLength, + config.momentumBarApprovedMultiplier // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + IsXBullish(iDir) && + canDetectBullish; + isBearish = has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iDir // + ); + } + } + + // + // Engulfed ... + iPattern = X_BAR_PATTERN_ENGULFED; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = IsEngulfedBar( + bar, + iDir // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + IsXBullish(iDir) && + canDetectBullish; + isBearish = has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iDir // + ); + } + } + + // + // TrueGap ... + iPattern = X_BAR_PATTERN_TRUE_GAPED; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = IsTrueGapedBar( + bar, + iDir, + config.trueGapApprovedStrength // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + IsXBullish(iDir) && + canDetectBullish; + isBearish = has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iDir // + ); + } + } + + // + // Pinned ... + iPattern = X_BAR_PATTERN_PINNED; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = IsPinnedBar( + bar, + iDir, + config.pinBarShadowApprovedMultiplier, + config.pinBarRangeMultiplier, + config.pinBarForceDirection // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + IsXBullish(iDir) && + canDetectBullish; + isBearish = has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iDir // + ); + } + } + + // + // Pattern Detectors ... + + // + // Star ... + iPattern = X_BAR_PATTERN_STAR; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = IsStarPattern( + bar, + iDir // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + IsXBullish(iDir) && + canDetectBullish; + isBearish = has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iDir // + ); + } + } + + // + // Piercing ... + iPattern = X_BAR_PATTERN_PIERCING; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = IsPiercingPattern( + bar, + iDir // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + IsXBullish(iDir) && + canDetectBullish; + isBearish = has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iDir // + ); + } + } + + // + // Rising ... + iPattern = X_BAR_PATTERN_RISING; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = IsRisingPattern( + bar, + iDir // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + IsXBullish(iDir) && + canDetectBullish; + isBearish = has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iDir // + ); + } + } + + // + // Flag ... + iPattern = X_BAR_PATTERN_FLAG; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = IsFlagPattern( + bar, + iDir, + iSwing, + config.flagPatternPullbackLength // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + IsXBullish(iDir) && + canDetectBullish; + isBearish = has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iDir // + ); + + // + analysis.flagSwing = iSwing; + } + } + + // + // SignalKey ... + iPattern = X_BAR_PATTERN_SIGNALKEY; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = IsSignalKeyBarPattern( + bar, + iDir, + config.pinBarShadowApprovedMultiplier, + config.pinBarRangeMultiplier, + config.pinBarForceDirection // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + IsXBullish(iDir) && + canDetectBullish; + isBearish = has && + IsXBearish(iDir) && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iDir // + ); + } + } + + // + // Zone Detectors ... + + // + // OB ... + iPattern = X_BAR_PATTERN_OB; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = barAnalyser.IsOB( + bar, + iZone, + config.fvgForceType, + config.obForceTwoBar // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + iZone.IsBullish() && + canDetectBullish; + isBearish = has && + iZone.IsBearish() && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iZone.dir // + ); + + // + analysis.ob = iZone; + } + } + + // + // FVG ... + iPattern = X_BAR_PATTERN_FVG; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = barAnalyser.IsFVG( + bar, + iZone, + config.fvgForceType // + ); + + // + canDetectBullish = config.CanDetect( + iPattern, + X_DIRECTION_BULLISH // + ); + canDetectBearish = config.CanDetect( + iPattern, + X_DIRECTION_BEARISH // + ); + + // + isBullish = has && + iZone.IsBullish() && + canDetectBullish; + isBearish = has && + iZone.IsBearish() && + canDetectBearish; + + // + canDetect = isBullish || + isBearish; + if (canDetect) + { + // + analysis.AddPattern( + iPattern, + iZone.dir // + ); + + // + analysis.fvg = iZone; + } + } + + // + // Support ... + iPattern = X_BAR_PATTERN_SUPPORT; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = HasSupport( + bar, + iSwing, + config.supportAndResistanceValidationLength, + config.supportAndResistanceLoopbackLength // + ); + if (has) + { + // + has = ToSupportBox( + iSwing, + iZone, + bar.time, + config.supportAndResistanceValidationLength // + ); + if (has) + { + // + analysis.AddPattern( + iPattern, + iZone.dir // + ); + + // + analysis.support = iZone; + } + } + } + + // + // Resistance ... + iPattern = X_BAR_PATTERN_RESISTANCE; + canDetect = config.CanDetect(iPattern); + if (canDetect) + { + // + has = HasResistance( + bar, + iSwing, + config.supportAndResistanceValidationLength, + config.supportAndResistanceLoopbackLength // + ); + if (has) + { + // + has = ToResistanceBox( + iSwing, + iZone, + bar.time, + config.supportAndResistanceValidationLength // + ); + if (has) + { + // + analysis.AddPattern( + iPattern, + iZone.dir // + ); + + // + analysis.resistance = iZone; + } + } + } + + // + // Validate Analysis ... + result = analysis.IsValid(); + + // + // Cleanup Resources ... + iZone.Clean(); + iSwing.Clean(); + CleanDirection(iDir); + + // + return result; + } + + /** + * Collect Required Order Blocks ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param dest: XBoxZone, collection reference to holds detected zones ... + * @param zonesLoopback: int, zones detection loopback ... + * @param maxRequiredZone: int, number of required zones ... + * @param loopback: int, max allowed loopback lenght for zone Detection ... + * + * @return ( int ) + */ + int CollectOBs( + XOHCL &bar, + XBoxZone &dest[], + int zonesLoopback = 5, + int maxRequiredZone = 0, + int loopback = 100 // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 10); + zonesLoopback = NormalizeInt(zonesLoopback, 3); + maxRequiredZone = NormalizeInt(maxRequiredZone, 0); + + // + // Validate ... + bool has = bar.IsValid(); + if (!has) + { + return result; + } + + // + XOHCL iBar; + XBoxZone iBox; + ENUM_X_DIRECTION iDir; + int start = bar.Index(); + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + iBox.Clean(); + iDir = X_DIRECTION_NONE; + + // + has = bar.BarAt(i, iBar); + has = has && + HasOB(iBar, iDir, iBox, zonesLoopback); + if (has) + { + // + AddIfNotExists( + iBox, + dest // + ); + } + + // + has = maxRequiredZone <= 0 || + (maxRequiredZone > 0 && ArraySize(dest) < maxRequiredZone); + if (!has) + { + break; + } + } + + // + result = ArraySize(dest); + + // + // Cleanup ... + iBar.Clean(); + iBox.Clean(); + iDir = X_DIRECTION_NONE; + + // + return result; + } + + /** + * Collect Required Fair Value Gaps ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param dest: XBoxZone, collection reference to holds detected zones ... + * @param zonesLoopback: int, zones detection loopback ... + * @param maxRequiredZone: int, number of required zones ... + * @param loopback: int, max allowed loopback lenght for zone Detection ... + * + * @return ( int ) + */ + int CollectFVGs( + XOHCL &bar, + XBoxZone &dest[], + int zonesLoopback = 5, + int maxRequiredZone = 0, + int loopback = 100 // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 10); + zonesLoopback = NormalizeInt(zonesLoopback, 3); + maxRequiredZone = NormalizeInt(maxRequiredZone, 0); + + // + // Validate ... + bool has = bar.IsValid(); + if (!has) + { + return result; + } + + // + XOHCL iBar; + XBoxZone iBox; + ENUM_X_DIRECTION iDir; + int start = bar.Index(); + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + iBox.Clean(); + iDir = X_DIRECTION_NONE; + + // + has = bar.BarAt(i, iBar); + has = has && + HasFVG(iBar, iDir, iBox, zonesLoopback); + if (has) + { + // + AddIfNotExists( + iBox, + dest // + ); + } + + // + has = maxRequiredZone <= 0 || + (maxRequiredZone > 0 && ArraySize(dest) < maxRequiredZone); + if (!has) + { + break; + } + } + + // + result = ArraySize(dest); + + // + // Cleanup ... + iBar.Clean(); + iBox.Clean(); + iDir = X_DIRECTION_NONE; + + // + return result; + } + + /** + * Collect Required Support and Resistance Zones ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param dest: XBoxZone, collection reference to holds detected zones ... + * @param zonesLoopback: int, zones detection loopback ... + * @param zonesValidationLength: int, zones validation length ... + * @param maxRequiredZone: int, number of required zones ... + * @param loopback: int, max allowed loopback lenght for zone Detection ... + * + * @return ( int ) + */ + int CollectZones( + XOHCL &bar, + XBoxZone &dest[], + int zonesLoopback = 5, + int zonesValidationLength = 21, + int maxRequiredZone = 0, + int loopback = 100 // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 10); + zonesLoopback = NormalizeInt(zonesLoopback, 3); + maxRequiredZone = NormalizeInt(maxRequiredZone, 0); + zonesValidationLength = NormalizeInt(zonesValidationLength, 3); + + // + // Validate ... + bool has = bar.IsValid(); + if (!has) + { + return result; + } + + // + XOHCL iBar; + XBoxZone iBox; + XOHCL iZoneBar; + int start = bar.Index(); + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + iBox.Clean(); + iZoneBar.Clean(); + + // + has = bar.BarAt(i, iBar); + if (!has) + { + continue; + } + + // + // Support ... + has = HasSupport(iBar, iZoneBar, zonesValidationLength, zonesLoopback); + if (has) + { + // + has = ToSupportBox(iZoneBar, iBox, bar.time, zonesValidationLength); + if (has) + { + // + AddIfNotExists( + iBox, + dest // + ); + } + } + + // + // Resistance ... + has = HasResistance(iBar, iZoneBar, zonesValidationLength, zonesLoopback); + if (has) + { + // + has = ToResistanceBox(iZoneBar, iBox, bar.time, zonesValidationLength); + if (has) + { + // + AddIfNotExists( + iBox, + dest // + ); + } + } + + // + has = maxRequiredZone <= 0 || + (maxRequiredZone > 0 && ArraySize(dest) < maxRequiredZone); + if (!has) + { + break; + } + } + + // + result = ArraySize(dest); + + // + // Cleanup ... + iBar.Clean(); + iBox.Clean(); + iZoneBar.Clean(); + + // + return result; + } + + /** + * Detect and Collect Required Zones ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param zones: XBoxZone, collection reference to holds detected zones ... + * @param validateZones: bool, Specified to Detect only Valid Zones ... + * @param containsOBs: bool, Flag to use Order Block Zones ... + * @param containsFVGs: bool, Flag to use Fair Value Gap Zones ... + * @param containsSupports: bool, Flag to use Support Zones ... + * @param containsResistancess: bool, Flag to use Resistance Zones ... + * @param forDir: ENUM_X_DIRECTION, Specified Zones Direction for Detecting ... + * @param sortby: ENUM_X_SORT_BY, Specified Zones Sorting Factor ... + * @param sortDir: ENUM_X_DIRECTION, Specified Zones Sorting Direction ... + * @param zonesRangeValidationFactor: double, Specified Zones Range Validation in Points ... + * @param zonesLoopback: int, loop back for Zones Detection ... + * @param zonesValidationLength: int, zones Validation Length ... + * @param count: int, number of required Zones ... + * @param loopback: int, max allowed looping back lenght for detection ... + * + * @return ( int ) + */ + int DetectZones( + XOHCL &bar, + XBoxZone &zones[], + bool validateZones = true, + bool containsOBs = true, + bool containsFVGs = true, + bool containsSupports = true, + bool containsResistancess = true, + int loopback = 500, + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE, + ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE, + ENUM_X_DIRECTION sortDir = X_DIRECTION_BEARISH, + double zonesRangeValidationFactor = 10, + int zonesLoopback = 5, + int zonesValidationLength = 5, + int count = 0 // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(zones); + + // + // Normalize ... + count = NormalizeInt(count, 0); + loopback = NormalizeInt(loopback, 50); + zonesLoopback = NormalizeInt(zonesLoopback, 2); + zonesValidationLength = NormalizeInt(zonesValidationLength, 3); + + // + // Validate ... + bool has = bar.IsValid() && + IsXValid(sortDir) && + IsXValid(sortBy) && + (containsOBs || containsFVGs || containsSupports || containsResistancess); + if (!has) + { + return result; + } + + // + XOHCL iBar; + XOHCL tmpBar; + XPivot tmpPivot; + XBoxZone tmpZone; + ENUM_X_DIRECTION tmpDir; + int idx = bar.Index(); + while (idx < bar.Index() + loopback) + { + // + idx++; + + // + iBar.Clean(); + tmpBar.Clean(); + tmpZone.Clean(); + tmpPivot.Clean(); + + // + has = bar.BarAt(idx, iBar); + if (!has) + { + continue; + } + + // + // Collecting Zones ... + + // + // Support ... + if (containsSupports) + { + // + if (!HasDirection(forDir) || IsXBullish(forDir)) + { + // + has = HasSupport(iBar, tmpBar, zonesValidationLength, zonesLoopback); + if (has) + { + // + has = ToBox(tmpBar, tmpZone, X_DIRECTION_BULLISH, X_BAR_PATTERN_SUPPORT); + if (has) + { + AddIfNotExists(tmpZone, zones); + } + } + } + } + + // + // Resistance ... + if (containsResistancess) + { + // + if (!HasDirection(forDir) || IsXBearish(forDir)) + { + // + has = HasResistance(iBar, tmpBar, zonesValidationLength, zonesLoopback); + if (has) + { + // + has = ToBox(tmpBar, tmpZone, X_DIRECTION_BEARISH, X_BAR_PATTERN_RESISTANCE); + if (has) + { + AddIfNotExists(tmpZone, zones); + } + } + } + } + + // + // Order Block ... + if (containsOBs) + { + // + has = HasOB(iBar, tmpDir, tmpZone, zonesLoopback); + if (has && (!HasDirection(forDir) || tmpDir == forDir)) + { + AddIfNotExists(tmpZone, zones); + } + } + + // + // Fair Value Gaps ... + if (containsFVGs) + { + // + has = HasFVG(iBar, tmpDir, tmpZone, zonesLoopback); + if (has && (!HasDirection(forDir) || tmpDir == forDir)) + { + AddIfNotExists(tmpZone, zones); + } + } + } + + // + // Validate Zones Exists ... + result = ArraySize(zones); + has = IsValidSize(result); + if (!has) + { + return result; + } + + // + // Update Zones Time ... + UpdateToTime(zones, bar.time); + + // + // Validate Zones ... + if (validateZones) + { + // + // Apply Zones Validation Here ... + RemoveBreakedZones(zones, true); + } + + // + // Validate Zones Range ... + if (zonesRangeValidationFactor > 0) + { + // + double points = GetPoints(bar.symbol); + double minAllowedRange = points * zonesRangeValidationFactor; + ValidateZonesRange(zones, minAllowedRange); + } + + // + // Apply Sorting ... + Sort(zones, sortBy, sortDir); + + // + // Validate Zones Count ... + if (count > 0) + { + CleanupArray(zones, count); + } + + // + result = ArraySize(zones); + + // + // Cleanup ... + iBar.Clean(); + tmpBar.Clean(); + tmpZone.Clean(); + tmpPivot.Clean(); + + // + return result; + } + + /** + * Filter Zones ... + * + * @param bar: XOHCL, reference to Specified Filtering Bar ... + * @param source: XBoxZone, reference collection to hold's filtered zones ... + * @param filterDir: ENUM_X_DIRECTION, specified Filter Direction ... + * @param priceType: ENUM_X_PRICE, Specified Bar's Price type to Use for Filtering Zones ... + * @param forDir: ENUM_X_DIRECTION, Specified Zone's Direction to Handle Filtering ... + * + * @return ( int ) + */ + int FilterZones( + XOHCL &bar, + XBoxZone &source[], + ENUM_X_DIRECTION filterDir, + ENUM_X_PRICE priceType = X_PRICE_CLOSE, + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + int result = 0; + + // + // Prepare ... + XBoxZone tmp[]; + Copy( + source, + tmp // + ); + XClean(source); + + // + // Validate ... + bool has = bar.IsValid() && + HasChild(tmp) && + IsXValid(priceType) && + HasDirection(filterDir); + if (!has) + { + // + XClean(tmp); + return result; + } + + // + XBoxZone iBox; + double price = bar.GetPrice(priceType); + bool isBullish = IsXBullish(filterDir); + while (HasChild(tmp)) + { + // + iBox = tmp[0]; + ArrayRemove(tmp, 0, 1); + + // + has = + // + // Direction Pass ... + (!HasDirection(forDir) + ? true + : forDir == iBox.dir) + // + && + // + // Price Pass ... + (isBullish + ? price > iBox.lower + : price < iBox.upper); + if (has) + { + AddIfNotExists(iBox, source); + } + + // + iBox.Clean(); + } + + // + result = ArraySize(source); + + // + // Cleanup ... + XClean(tmp); + iBox.Clean(); + + // + return result; + } + + // + // Protected ... + protected: + // + + // + // Tools / Actions ... + + /** + * Check Zones and Manage them ... + * + * @param forBar: XOHCL, reference to Specified Bar ... + * @param _zones: XBoxZone, reference to Specified Zone Collection ... + * @param sortBy: X_SORT_BY_DATE, Sort Zones by ... + * @param sortDir: ENUM_X_DIRECTION, Sort Zones in Direction ... + * @param maxAllowed: int, Specified Max Allowed Zones ... + */ + void CheckZones( + XOHCL &forBar, + XBoxZone &_zones[], + ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE, + ENUM_X_DIRECTION sortDir = X_DIRECTION_BEARISH, + int maxAllowed = 50 // + ) + { + // + // Normalize ... + maxAllowed = NormalizeInt(maxAllowed, 0); + + // + // Validate ... + bool has = forBar.IsValid() && + HasChild(_zones); + if (!has) + { + return; + } + + // + // Looping Through Zones ... + int count = ArraySize(_zones); + for (int i = 0; i < count; i++) + { + // + // Check Break ... + has = IsXValid(_zones[i].breakAt); + if (has) + { + continue; + } + + // + _zones[i].to = forBar.time; + + // + // Check for Test ... + has = IsTested( + forBar, + _zones[i] // + ); + if (has) + { + // + Add( + forBar.time, + _zones[i].tests // + ); + } + + // + // Check for Inside ... + has = IsInside( + forBar, + _zones[i] // + ); + if (has) + { + // + Add( + forBar.time, + _zones[i].insides // + ); + } + + // + // Check for Break ... + has = IsBreaked( + forBar, + _zones[i] // + ); + if (has) + { + // + Add( + forBar.time, + _zones[i].breaks // + ); + } + + // + // Check for Act ... + has = IsActed( + forBar, + _zones[i] // + ); + if (has) + { + // + Add( + forBar.time, + _zones[i].acteds // + ); + } + + // + // Check for FakeBreakes ... + has = IsFakeBreaked( + forBar, + _zones[i] // + ); + if (has) + { + // + Add( + forBar.time, + _zones[i].fakeBreaks // + ); + } + + // + // Check for Valid Breakes ... + has = IsValidBreaked( + forBar, + _zones[i] // + ); + if (has) + { + _zones[i].breakAt = forBar.time; + } + } + + // + // Apply Sort and Cleanup ... + Sort( + _zones, + sortBy, + sortDir, + maxAllowed // + ); + } + + // + // Private ... + private: + // + // Props ... + XCBarAnalyser *barAnalyser; + + // + // Helpers ... + + /** + * Clean Specified Referenced Direction ... + * + * @param dir: ENUM_X_DIRECTION + */ + void CleanDirection(ENUM_X_DIRECTION &dir) + { + dir = X_DIRECTION_NONE; + } +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-md5.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCMD5 +// Description: Provides MD5 Hashing Requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// START Definitions ... +// + +// +static uchar _md5_PADDING[64] = + { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +// +#define _md5_F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define _md5_G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define _md5_H(x, y, z) ((x) ^ (y) ^ (z)) +#define _md5_I(x, y, z) ((y) ^ ((x) | (~z))) +#define _md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +// +#define _md5_FF(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_F((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_GG(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_G((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_HH(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_H((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_II(a, b, c, d, x, s, ac) \ + { \ + (a) += _md5_I((b), (c), (d)) + (x) + (uint)(ac); \ + (a) = _md5_ROTATE_LEFT((a), (s)); \ + (a) += (b); \ + } + +// +#define _md5_INIT_STATE_0 0x67452301 +#define _md5_INIT_STATE_1 0xefcdab89 +#define _md5_INIT_STATE_2 0x98badcfe +#define _md5_INIT_STATE_3 0x10325476 + +// +#define _md5_S11 7 +#define _md5_S12 12 +#define _md5_S13 17 +#define _md5_S14 22 + +// +#define _md5_S21 5 +#define _md5_S22 9 +#define _md5_S23 14 +#define _md5_S24 20 + +// +#define _md5_S31 4 +#define _md5_S32 11 +#define _md5_S33 16 +#define _md5_S34 23 + +// +#define _md5_S41 6 +#define _md5_S42 10 +#define _md5_S43 15 +#define _md5_S44 21 + +// +// END Definitions ... +// + +// +// XCMD5 a library for Hashing ... +class XCMD5 +{ + // + // Public Provides ... + public: + // + // Protected Provides ... + + // + // Constructor ... + XCMD5(void) + { + } + + // + // Deconstructor ... + ~XCMD5(void) + { + } + + // + // Hash Specified Char Array ... + string Hash( + uchar &mSource[], // Specify Char Array to Hash + int mLength = 0 // Specify Length of Char Array which required to hash + ) + { + // + string result = ""; + + // + int sourceCount = ArraySize(mSource); + + // + // Validate Args ... + if ( + sourceCount <= 0 || + (sourceCount > 0 && mLength > sourceCount)) + { + return result; + } + + // + // Normalize Args ... + if (mLength == 0) + { + mLength = sourceCount; + } + + // + // Init MD5 ... + MD5Init(); + + // + // Update Buffer ... + MD5Update(mSource, mLength); + + // + // Calculate Result ... + result = MD5Final(); + + // + return result; + } + + // + // Hash Specified String ... + string Hash( + string mSource // Specified String + ) + { + // + string result = ""; + + // + // Converts String to Char Array ... + uchar bytes[]; + StringToCharArray( + mSource, + bytes, + 0, + StringLen(mSource)); + + // + result = Hash( + bytes, + ArraySize(bytes)); + + // + return result; + } + + protected: + // + // Private Provides ... + private: + // + uint m_lMD5[4]; + uint m_nCount[2]; + uchar m_lpszBuffer[64]; + + // + // Convert Byte to DWord ... + void ByteToDWord(int &out[], uint &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + out[i] = (int)in[j] | (int)in[j + 1] << 8 | (int)in[j + 2] << 16 | (int)in[j + 3] << 24; + } + } + + // + // Convert DWord to Byte ... + void DWordToByte(uchar &out[], uint &in[], uint len) + { + // + uint i = 0; + uint j = 0; + + // + for (; j < len; i++, j += 4) + { + // + out[j] = (uchar)(in[i] & 0xff); + out[j + 1] = (uchar)((in[i] >> 8) & 0xff); + out[j + 2] = (uchar)((in[i] >> 16) & 0xff); + out[j + 3] = (uchar)((in[i] >> 24) & 0xff); + } + } + + // + // Init MD5 Array ... + void MD5Init() + { + // + ArrayInitialize(m_lpszBuffer, 64); + + // + m_nCount[0] = m_nCount[1] = 0; + m_lMD5[0] = _md5_INIT_STATE_0; + m_lMD5[1] = _md5_INIT_STATE_1; + m_lMD5[2] = _md5_INIT_STATE_2; + m_lMD5[3] = _md5_INIT_STATE_3; + } + + // + // Update MD5 ... + void MD5Update(uchar &inBuf[], uint inLen) + { + // + int i, ii; + int mdi; + + // + uint in[16]; + int i0 = 0; + + // + mdi = (int)((m_nCount[0] >> 3) & 0x3F); + + // + if ((m_nCount[0] + ((uint)inLen << 3)) < m_nCount[0]) + { + m_nCount[1]++; + } + + // + m_nCount[0] += ((uint)inLen << 3); + m_nCount[1] += ((uint)inLen >> 29); + + // + while ((inLen--) > 0) + { + // + m_lpszBuffer[mdi++] = inBuf[i0++]; + if (mdi == 0x40) + { + // + for (i = 0, ii = 0; i < 16; i++, ii += 4) + { + in[i] = (((uint)m_lpszBuffer[ii + 3]) << 24) | (((uint)m_lpszBuffer[ii + 2]) << 16) | (((uint)m_lpszBuffer[ii + 1]) << 8) | ((uint)m_lpszBuffer[ii]); + } + + // + Transform(m_lMD5, in); + + // + mdi = 0; + } + } + } + + // + // Finalize an MD5 Expression ... + string MD5Final() + { + // + uchar bits[8]; + int nIndex; + uint nPadLen; + const int nMD5Size = 16; + uchar lpszMD5[16]; + string temp; + string out = ""; + int i; + + // + DWordToByte(bits, m_nCount, 8); + nIndex = (int)((m_nCount[0] >> 3) & 0x3f); + nPadLen = (nIndex < 56) ? (56 - nIndex) : (120 - nIndex); + MD5Update(_md5_PADDING, nPadLen); + MD5Update(bits, 8); + DWordToByte(lpszMD5, m_lMD5, nMD5Size); + + // + for (i = 0; i < nMD5Size; i++) + { + // + if (lpszMD5[i] == 0) + { + temp = "00"; + } + else if (lpszMD5[i] <= 15) + { + temp = StringFormat("0%x", lpszMD5[i]); + } + else + { + temp = StringFormat("%x", lpszMD5[i]); + } + + // + out += temp; + } + + // + lpszMD5[0] = '\0'; + + // + return (out); + } + + // + // Transform Buffers ... + void Transform(uint &buf[], uint &in[]) + { + // + uint a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + // + _md5_FF(a, b, c, d, in[0], _md5_S11, 0xD76AA478); + _md5_FF(d, a, b, c, in[1], _md5_S12, 0xE8C7B756); + _md5_FF(c, d, a, b, in[2], _md5_S13, 0x242070DB); + _md5_FF(b, c, d, a, in[3], _md5_S14, 0xC1BDCEEE); + _md5_FF(a, b, c, d, in[4], _md5_S11, 0xF57C0FAF); + _md5_FF(d, a, b, c, in[5], _md5_S12, 0x4787C62A); + _md5_FF(c, d, a, b, in[6], _md5_S13, 0xA8304613); + _md5_FF(b, c, d, a, in[7], _md5_S14, 0xFD469501); + _md5_FF(a, b, c, d, in[8], _md5_S11, 0x698098D8); + _md5_FF(d, a, b, c, in[9], _md5_S12, 0x8B44F7AF); + _md5_FF(c, d, a, b, in[10], _md5_S13, 0xFFFF5BB1); + _md5_FF(b, c, d, a, in[11], _md5_S14, 0x895CD7BE); + _md5_FF(a, b, c, d, in[12], _md5_S11, 0x6B901122); + _md5_FF(d, a, b, c, in[13], _md5_S12, 0xFD987193); + _md5_FF(c, d, a, b, in[14], _md5_S13, 0xA679438E); + _md5_FF(b, c, d, a, in[15], _md5_S14, 0x49B40821); + + // + _md5_GG(a, b, c, d, in[1], _md5_S21, 0xF61E2562); + _md5_GG(d, a, b, c, in[6], _md5_S22, 0xC040B340); + _md5_GG(c, d, a, b, in[11], _md5_S23, 0x265E5A51); + _md5_GG(b, c, d, a, in[0], _md5_S24, 0xE9B6C7AA); + _md5_GG(a, b, c, d, in[5], _md5_S21, 0xD62F105D); + _md5_GG(d, a, b, c, in[10], _md5_S22, 0x02441453); + _md5_GG(c, d, a, b, in[15], _md5_S23, 0xD8A1E681); + _md5_GG(b, c, d, a, in[4], _md5_S24, 0xE7D3FBC8); + _md5_GG(a, b, c, d, in[9], _md5_S21, 0x21E1CDE6); + _md5_GG(d, a, b, c, in[14], _md5_S22, 0xC33707D6); + _md5_GG(c, d, a, b, in[3], _md5_S23, 0xF4D50D87); + _md5_GG(b, c, d, a, in[8], _md5_S24, 0x455A14ED); + _md5_GG(a, b, c, d, in[13], _md5_S21, 0xA9E3E905); + _md5_GG(d, a, b, c, in[2], _md5_S22, 0xFCEFA3F8); + _md5_GG(c, d, a, b, in[7], _md5_S23, 0x676F02D9); + _md5_GG(b, c, d, a, in[12], _md5_S24, 0x8D2A4C8A); + + // + _md5_HH(a, b, c, d, in[5], _md5_S31, 0xFFFA3942); + _md5_HH(d, a, b, c, in[8], _md5_S32, 0x8771F681); + _md5_HH(c, d, a, b, in[11], _md5_S33, 0x6D9D6122); + _md5_HH(b, c, d, a, in[14], _md5_S34, 0xFDE5380C); + _md5_HH(a, b, c, d, in[1], _md5_S31, 0xA4BEEA44); + _md5_HH(d, a, b, c, in[4], _md5_S32, 0x4BDECFA9); + _md5_HH(c, d, a, b, in[7], _md5_S33, 0xF6BB4B60); + _md5_HH(b, c, d, a, in[10], _md5_S34, 0xBEBFBC70); + _md5_HH(a, b, c, d, in[13], _md5_S31, 0x289B7EC6); + _md5_HH(d, a, b, c, in[0], _md5_S32, 0xEAA127FA); + _md5_HH(c, d, a, b, in[3], _md5_S33, 0xD4EF3085); + _md5_HH(b, c, d, a, in[6], _md5_S34, 0x04881D05); + _md5_HH(a, b, c, d, in[9], _md5_S31, 0xD9D4D039); + _md5_HH(d, a, b, c, in[12], _md5_S32, 0xE6DB99E5); + _md5_HH(c, d, a, b, in[15], _md5_S33, 0x1FA27CF8); + _md5_HH(b, c, d, a, in[2], _md5_S34, 0xC4AC5665); + + // + _md5_II(a, b, c, d, in[0], _md5_S41, 0xF4292244); + _md5_II(d, a, b, c, in[7], _md5_S42, 0x432AFF97); + _md5_II(c, d, a, b, in[14], _md5_S43, 0xAB9423A7); + _md5_II(b, c, d, a, in[5], _md5_S44, 0xFC93A039); + _md5_II(a, b, c, d, in[12], _md5_S41, 0x655B59C3); + _md5_II(d, a, b, c, in[3], _md5_S42, 0x8F0CCC92); + _md5_II(c, d, a, b, in[10], _md5_S43, 0xFFEFF47D); + _md5_II(b, c, d, a, in[1], _md5_S44, 0x85845DD1); + _md5_II(a, b, c, d, in[8], _md5_S41, 0x6FA87E4F); + _md5_II(d, a, b, c, in[15], _md5_S42, 0xFE2CE6E0); + _md5_II(c, d, a, b, in[6], _md5_S43, 0xA3014314); + _md5_II(b, c, d, a, in[13], _md5_S44, 0x4E0811A1); + _md5_II(a, b, c, d, in[4], _md5_S41, 0xF7537E82); + _md5_II(d, a, b, c, in[11], _md5_S42, 0xBD3AF235); + _md5_II(c, d, a, b, in[2], _md5_S43, 0x2AD7D2BB); + _md5_II(b, c, d, a, in[9], _md5_S44, 0xEB86D391); + + // + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; + } +}; + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-poi.drawer.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XPOIDrawer +// Description: Provides Point of Interests +// Drawing Tools ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-cobject.class.mq5" +#include "../Libraries/x-saherelm.x-pivot.analysis.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" + +// +// Definitions ... + +// +// Implementations ... +class XCPOIDrawer : public XCBase +{ + // + public: + // + // Props ... + + // + XPOIStyle defaultBullishStyle; + XPOIStyle defaultBearishStyle; + + // + XPOIStyle boxBullishStyle; + XPOIStyle boxBearishStyle; + + // + CArrayObj drawnObjects; + + // + // Constructor ... + XCPOIDrawer() + { + // + Default(); + } + + // + // Deconstructor ... + ~XCPOIDrawer() + { + // + boxBullishStyle.Clean(); + boxBearishStyle.Clean(); + defaultBullishStyle.Clean(); + defaultBearishStyle.Clean(); + } + + // + // Setter Getter (s) ... + + /** + * Get Prefix ... + * + * @return ( string ) + */ + string Prefix() + { + return mPrefix; + } + + /** + * Set Prifx ... + * + * @param value: String ... + */ + void Prefix(string value) + { + mPrefix = value; + } + + /** + * Get Chart ID ... + * + * @return ( long ) + */ + long ChartIdentification() + { + return mChartIdentification; + } + + /** + * Set Chart ID ... + * + * @param value: Long ... + */ + void ChartIdentification(long value) + { + // + if (value < 0) + { + value = 0; + } + + // + mChartIdentification = value; + } + + /** + * Get SubWindow Id ... + * + * @return ( int ) + */ + int SubWindowIdentification() + { + return mSubWindowIdentification; + } + + /** + * Set SubWindow Id ... + * + * @param value: Integer ... + */ + void SubWindowIdentification(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mSubWindowIdentification = value; + } + + // + // Virtuals ... + + /** + * Apply Default Configurations ... + */ + virtual void Default() + { + // + // Apply Default Props ... + + // + Prefix(NULL); + ChartIdentification(0); + SubWindowIdentification(0); + + // + defaultBullishStyle.width = 1; + defaultBullishStyle.clr = clrLime; + defaultBullishStyle.style = STYLE_SOLID; + + // + defaultBearishStyle.width = 1; + defaultBearishStyle.clr = clrRed; + defaultBearishStyle.style = STYLE_SOLID; + + // + boxBullishStyle = defaultBullishStyle; + boxBearishStyle = defaultBearishStyle; + } + + // + // Drawers ... + + /** + * Draw Specified Bar ... + * + * @param bar: XOHCL, refrence to Specified Bar ... + * @param object: XCOHCLObject, pointer reference for Drawn Object ... + * @param to: datetime, Specified To Time ... + * + * @return ( bool ) + */ + bool DrawBar( + XOHCL &bar, + XCOHCLObject *&object, + datetime to = NULL // + ) + { + // + bool result = false; + + // + // Prepare ... + object = NULL; + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + ulong chartId = ChartIdentification(); + int window = SubWindowIdentification(); + to = IsSpecifiedValid(to) + ? to + : ((datetime)((int)bar.time) + (PeriodSeconds(bar.period) - 1)); + object = new XCOHCLObject(); + result = object.Create( + chartId, + window, + bar, + to, + prefix // + ); + if (result) + { + // + ApplyBarStyle( + object, + bar // + ); + } + + // + return result; + } + + /** + * Draw Bar Arrow Object ... + * + * @param bar: XOHCL instance Reference ... + * @param object: XCBarArrowObject, pointer reference for Drawn Object ... + * @param priceType: ENUM_X_PRICE member ... + * @param arrow: int, Arrow Code ... + * @param clr: color, Arro Color ... + * @param width: int, Arrow Width ... + * @param anchor: ENUM_ARROW_ANCHOR, anchor of Arrow ... + * @param name: string, name of Arrow ... + * + * @return ( bool ) + */ + bool DrawBarArrow( + XOHCL &bar, + XCBarArrowObject *&object, + ENUM_X_PRICE priceType, + int arrow = 159, + color clr = clrYellow, + int width = 3, + ENUM_ARROW_ANCHOR anchor = ANCHOR_BOTTOM, + string name = NULL, + bool ignoreBarTag = true, + int threshold = 5 // + ) + { + // + bool result = false; + + // + object = NULL; + + // + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + string barTag = bar.GetTag(name); + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + prefix = + (IsValid(prefix) + ? prefix + "_" + : prefix) + + (IsSpecifiedValid(name) + ? name + : "") + + (ignoreBarTag ? "" : ToMD5(barTag)); + + // + object = new XCBarArrowObject(); + result = object + .CreateByBar( + chartID, + prefix, + window, + arrow, + bar, + priceType, + threshold // + ); + if (result) + { + // + object.ArrowColor(clr); + object.ArrowWidth(width); + object.ArrowAnchor(anchor); + } + + // + return result; + } + + /** + * Dar Specified Pivot ... + * + * @param pivot: XPivot, Specified Pivot ... + * @param object: XCBarArrowObject, pointer reference for Drawn Object ... + * @param peakArrow: int, Specified Arrow Code for Peak Pivots ... + * @param valeArrow: int, Specified Arrow Code for Vale Pivots ... + * @param threshold: int, distance between price and arrow in Point ... + * + * @return ( bool ) + */ + bool DrawPivot( + XPivot &pivot, + XCBarArrowObject *&object, + int peakArrow = 159, + int valeArrow = 159, + int threshold = 5 // + ) + { + // + bool result = false; + + // + // Prepare ... + object = NULL; + + // + // Normalize ... + threshold = NormalizeInt(threshold, 5); + peakArrow = NormalizeInt(peakArrow, 159); + valeArrow = NormalizeInt(valeArrow, 159); + + // + // Validate ... + result = pivot.IsValid(); + if (!result) + { + return result; + } + + // + // Get Pivot's Bar ... + XOHCL bar; + result = pivot.GetBar(bar); + if (!result) + { + return result; + } + + // + int arrow = pivot.IsPeak() + ? peakArrow + : valeArrow; + string name = pivot.GetObjectID(); + ENUM_X_PRICE type = pivot.IsPeak() + ? X_PRICE_HIGH + : X_PRICE_LOW; + XPOIStyle style = pivot.IsPeak() + ? defaultBearishStyle + : defaultBullishStyle; + ENUM_ARROW_ANCHOR anchor = pivot.IsPeak() + ? ANCHOR_BOTTOM + : ANCHOR_TOP; + object = new XCBarArrowObject(); + result = object.CreateByBar( + ChartIdentification(), + name, + SubWindowIdentification(), + arrow, + bar, + type, + threshold // + ); + if (result) + { + // + // Apply Styles ... + object.ArrowAnchor(anchor); + ApplyBarArrowStyle( + object, + style // + ); + } + + // + // Cleanup Resources ... + bar.Clean(); + + // + return result; + } + + /** + * Draw Specified Pivot Collection ... + * + * @param pivots: XPivot, reference Collection to Draw ... + * @param draws: CArrayObj, pointer reference to Hold Drawn Objects ... + * @param peakArrow: int, Specified Arrow Code for Peak Pivots ... + * @param valeArrow: int, Specified Arrow Code for Vale Pivots ... + * @param threshold: int, distance between price and arrow in Point ... + * + * @return ( int ) + */ + int DrawPivots( + XPivot &pivots[], + CArrayObj *&draws, + int peakArrow = 159, + int valeArrow = 159, + int threshold = 5 // + ) + { + // + int result = 0; + + // + // Prepare ... + if (draws == NULL) + { + draws = new CArrayObj(); + } + draws.Clear(); + + // + // Validate ... + if (!HasChild(pivots)) + { + return result; + } + + // + bool has = false; + XCBarArrowObject *iObj; + int count = ArraySize(pivots); + for (int i = 0; i < count; i++) + { + // + // Draw Indexed Pivot ... + has = DrawPivot( + pivots[i], + iObj, + peakArrow, + valeArrow, + threshold // + ); + + // + if (has) + { + draws.Add(iObj); + } + + // + ZeroMemory(iObj); + } + + // + result = draws.Total(); + + // + return result; + } + + /** + * Draw Specified Box ... + * + * @param object: XCBoxObject, pointer reference for Drawn Object ... + * @param name: Box Name ... + * @param upper: double, Box Upper ... + * @param lower: double, Box Lower ... + * @param from: datetime, From Time ... + * @param to: datetime, To Time ... + * @param at: datetime, Specified At Time ... + * + * @return ( bool ) + */ + bool DrawBox( + XCBoxObject *&object, + string name, + double upper, + double lower, + datetime from, + datetime to, + datetime at // + ) + { + // + bool result = false; + + // + // Prepare ... + object = NULL; + + // + // Normalize ... + to = NormalizeTime(to); + from = NormalizeTime(from); + + // + // Validate ... + result = + upper > 0 && + lower > 0 && + to > from && + IsSpecifiedValid(to) && + IsSpecifiedValid(name) && + IsSpecifiedValid(from) && + upper > lower; + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCBoxObject(); + result = object.Create( + chartID, + window, + name, + upper, + lower, + from, + to, + at, + prefix // + ); + + // + return result; + } + + /** + * Draw Specific Box ... + * + * @param box: XBoxZone, Specified Box ... + * @param object: XCBarArrowObject, pointer reference for Drawn Object ... + * @param ignoreAt: bool, Ignore Box at or not ... + * + * @return ( bool ) + */ + bool DrawBox( + XBoxZone &box, + XCBoxObject *&object, + bool ignoreAt = true, + string name = NULL // + ) + { + // + bool result = false; + + // + // Prepare ... + object = NULL; + + // + // Validate ... + result = box.IsValid(); + if (!result) + { + return result; + } + + // + datetime at = box.at; + if (ignoreAt) + { + at = NULL; + } + + // + name = IsSpecifiedValid(name) + ? name + : box.GetTag(); + result = DrawBox( + object, + name, + box.upper, + box.lower, + box.from, + box.to, + at // + ); + if (result) + { + // + // Apply Style ... + XPOIStyle style; + GetBoxStyle( + style, + box.dir // + ); + + // + ApplyBoxStyle( + object, + style // + ); + + // + style.Clean(); + } + + // + return result; + } + + /** + * Draw a Collection of Boxes ... + * + * @param boxes: reference collection to Provide Boxes ... + * @param objects: reference pointer to holds drawn Objects ... + * @param ignoreAt: bool, ignore Box At Drawn ... + * + * @return ( int ) + */ + int DrawBoxes( + XBoxZone &boxes[], + CArrayObj *&objects, + bool useTypeName = true, + bool ignoreAt = true // + ) + { + // + int result = 0; + + // + // Prepare ... + objects = new CArrayObj(); + + // + // Validate ... + if (!HasChild(boxes)) + { + return result; + } + + // + bool has = false; + XCBoxObject *iObj; + string name = NULL; + int count = ArraySize(boxes); + for (int i = 0; i < count; i++) + { + // + if (useTypeName) + { + name = boxes[i].type; + } + + // + has = DrawBox( + boxes[i], + iObj, + ignoreAt, + name // + ); + if (has) + { + objects.Add(iObj); + } + + // + ZeroMemory(iObj); + } + + // + result = objects.Total(); + + // + return result; + } + + /** + * Draw Specified Signal ... + * + * @param signal: XSignal, Specified Signal ... + * @param object: XCSignalObject, pointer reference for Drawn Object ... + * @param length: int, Signal Length ... + */ + bool DrawSignal( + XSignal &signal, + XCSignalObject *&object, + int length = 3 // + ) + { + // + bool result = false; + + // + object = NULL; + length = NormalizeInt(length, 3); + + // + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + string prefix = Prefix(); + long chartID = ChartIdentification(); + int window = SubWindowIdentification(); + + // + object = new XCSignalObject(); + result = object.Create( + chartID, + window, + signal, + length, + prefix // + ); + if (!result) + { + return result; + } + + // + object.TPWidth(1); + object.TPColor(clrGreen); + object.TPWidth(STYLE_DOT); + + // + object.SLWidth(1); + object.SLColor(clrRed); + object.SLWidth(STYLE_DOT); + + // + object.TargetWidth(1); + object.TargetColor(clrLightBlue); + object.TargetWidth(STYLE_DOT); + + // + object.EntryWidth(1); + object.EntryColor(clrYellow); + object.EntryWidth(STYLE_DOT); + + // + return result; + } + + /** + * Draw Specified Trend Line ... + * + * @param fromPrice: double, from Price ... + * @param fromTime: datetime, from Time ... + * @param toPrice: double, to Price ... + * @param toTime: datetime, to Time ... + * @param object: CChartObjectTrend, pointer reference for Drawn Object ... + * @param name: Object Name ... + * @param rayRight: bool, ray to Right ... + * @param rayLeft: boo, ray to Left ... + * + * @return ( bool ) + */ + bool DrawTrendLine( + double fromPrice, + datetime fromTime, + double toPrice, + datetime toTime, + CChartObjectTrend *&object, + string name, + bool rayRight = false, + bool rayLeft = false // + ) + { + // + bool result = false; + + // + // Prepare ... + object = new CChartObjectTrend(); + + // + // Validate ... + result = + toPrice > 0 && + fromPrice > 0 && + IsSpecifiedValid(toTime) && + IsSpecifiedValid(fromTime) && + toTime > fromTime; + if (!result) + { + return result; + } + + // + // Create Object ... + result = object.Create( + ChartIdentification(), + name, + SubWindowIdentification(), + fromTime, + fromPrice, + toTime, + toPrice // + ); + if (result) + { + // + ENUM_X_DIRECTION dir = + fromPrice < toPrice + ? X_DIRECTION_BULLISH + : fromPrice > toPrice + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + ApplyTrendLineStyle( + object, + dir // + ); + + // + object.RayLeft(rayLeft); + object.RayRight(rayRight); + } + + // + return result; + } + + /** + * Draw Trend Line based on Swings Points ... + * + * @param swings: XOHCL, Specified Swings ... + * @param dir: ENUM_X_DIRECTION, Specified Trend Direction ... + * @param object: CChartObjectTrend, pointer reference for Drawn Object ... + * @param rayRight: Ray to Right ... + * @param rayLeft: Ray to Left ... + * + * @return ( bool ) + */ + bool DrawSwingTrend( + XOHCL &swings[], + ENUM_X_DIRECTION dir, + CChartObjectTrend *&object, + bool rayRight = false, + bool rayLeft = false // + ) + { + // + bool result = false; + + // + // Prepare ... + object = NULL; + + // + int count = ArraySize(swings); + result = HasChild(swings) && + count >= 2 && + HasDirection(dir); + if (!result) + { + return result; + } + + // + bool isBullish = IsSpecifiedBullish(dir); + + // + XOHCL _swings[]; + Copy( + swings, + _swings // + ); + SortBar( + _swings, + X_SORT_BY_DATE, + X_DIRECTION_BULLISH // + ); + + // + double price1 = + isBullish + ? _swings[0].low + : _swings[0].high; + datetime time1 = _swings[0].time; + + // + double price2 = + isBullish + ? _swings[count - 1].low + : _swings[count - 1].high; + datetime time2 = _swings[count - 1].time; + + // + ulong chartId = ChartIdentification(); + int subWindow = SubWindowIdentification(); + string name = ToXString(dir) + "_Trend_" + ToXString(price1) + "_" + ToXString(price2); + RemoveObjects("_Trend_", chartId, subWindow); + + // + object = new CChartObjectTrend(); + result = object.Create( + chartId, + name, + subWindow, + time1, + price1, + time2, + price2 // + ); + if (result) + { + // + ApplyTrendLineStyle( + object, + dir // + ); + + // + object.RayLeft(rayLeft); + object.RayRight(rayRight); + } + + // + SpecifiedClean(_swings); + + // + return result; + } + + // + // Stylers ... + + /** + * Get Specified Style for Specified Direction ... + * + * @param style: XPOIStyle, reference to hold result ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + */ + void GetStyle( + XPOIStyle &style, + ENUM_X_DIRECTION forDir // + ) + { + // + // Prepare ... + style.Clean(); + + // + // Validate ... + if (!HasDirection(forDir)) + { + return; + } + + // + if (IsSpecifiedBullish(forDir)) + { + style = defaultBullishStyle; + } + else + { + style = defaultBearishStyle; + } + } + + /** + * Get Specified Box Style for Specified Direction ... + * + * @param style: XPOIStyle, reference to hold result ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + */ + void GetBoxStyle( + XPOIStyle &style, + ENUM_X_DIRECTION forDir // + ) + { + // + // Prepare ... + style.Clean(); + + // + // Validate ... + if (!HasDirection(forDir)) + { + return; + } + + // + if (IsSpecifiedBullish(forDir)) + { + style = boxBullishStyle; + } + else + { + style = boxBearishStyle; + } + } + + /** + * Apply Specified Style to Specified Object ... + * + * @param object: XCBoxObject, pointer reference of Object ... + * @param bar: XOHCL, Specified Bar ... + * @param fill: boolean, Fill Bar's Body or not ... + */ + void ApplyBarStyle( + XCOHCLObject *&object, + XOHCL &bar, + bool fill = false // + ) + { + // + // Validate ... + bool has = bar.IsValid() && + object != NULL; + if (!has) + { + return; + } + + // + XPOIStyle style; + GetStyle( + style, + bar.GetDirection() // + ); + + // + object.BarSpes( + style.width, + style.clr, + style.style, + fill // + ); + + // + style.Clean(); + } + + /** + * Apply Specified Style to Specified Object ... + * + * @param object: XCBoxObject, pointer reference of Object ... + * @param style: XPOIStyle, Specifed Style to Apply ... + */ + void ApplyBoxStyle( + XCBoxObject *&object, + XPOIStyle &style // + ) + { + // + bool has = object != NULL; + if (!has) + { + return; + } + + // + object.BoxFill(style.fill); + object.BoxColor(style.clr); + object.BoxWidth(style.width); + object.BoxStyle(style.style); + } + + /** + * Apply Specified Style to a Collection on Drawn Boxes ... + * + * @param objects: pointer reference of Objects ... + * @param style: XPOIStyle, Specifed Style to Apply ... + */ + void ApplyBoxesStyle( + CArrayObj *&objects, + XPOIStyle &style // + ) + { + // + // Validate ... + if (objects == NULL || objects.Total() <= 0) + { + return; + } + + // + for (int i = 0; i < objects.Total(); i++) + { + // + XCBoxObject *iObj = ((XCBoxObject *)objects.At(i)); + ApplyBoxStyle( + iObj, + style // + ); + ZeroMemory(iObj); + } + } + + /** + * Apply Specified Style to Specified Object ... + * + * @param object: XCBarArrowObject, pointer reference of Object ... + * @param style: XPOIStyle, Specifed Style to Apply ... + */ + void ApplyBarArrowStyle( + XCBarArrowObject *&object, + XPOIStyle &style // + ) + { + // + bool has = object != NULL; + if (!has) + { + return; + } + + // + object.ArrowColor(style.clr); + object.ArrowWidth(style.width); + } + + /** + * Apply Specified Style to Specified Object ... + * + * @param object: CChartObjectVLine, pointer reference of Object ... + * @param style: XPOIStyle, Specifed Style to Apply ... + */ + void ApplyLineStyle( + CChartObjectVLine *&object, + XPOIStyle &style // + ) + { + // + bool has = object != NULL; + if (!has) + { + return; + } + + // + object.Color(style.clr); + object.Style(style.style); + object.Width(style.width); + } + + /** + * Apply Specified Style to Specified Object ... + * + * @param object: CChartObjectVLine, pointer reference of Object ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + */ + void ApplyLineStyle( + CChartObjectVLine *&object, + ENUM_X_DIRECTION forDir // + ) + { + // + bool has = object != NULL; + if (!has) + { + return; + } + + // + has = HasDirection(forDir); + if (!has) + { + return; + } + + // + XPOIStyle style; + GetStyle(style, forDir); + + // + object.Color(style.clr); + object.Style(style.style); + object.Width(style.width); + + // + style.Clean(); + } + + /** + * Apply Specified Style to Specified Object ... + * + * @param object: CChartObjectHLine, pointer reference of Object ... + * @param style: XPOIStyle, Specifed Style to Apply ... + */ + void ApplyLineStyle( + CChartObjectHLine *&object, + XPOIStyle &style // + ) + { + // + bool has = object != NULL; + if (!has) + { + return; + } + + // + object.Color(style.clr); + object.Style(style.style); + object.Width(style.width); + } + + /** + * Apply Specified Style to Specified Object ... + * + * @param object: CChartObjectHLine, pointer reference of Object ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + */ + void ApplyLineStyle( + CChartObjectHLine *&object, + ENUM_X_DIRECTION forDir // + ) + { + // + bool has = object != NULL; + if (!has) + { + return; + } + + // + has = HasDirection(forDir); + if (!has) + { + return; + } + + // + XPOIStyle style; + GetStyle(style, forDir); + + // + object.Color(style.clr); + object.Style(style.style); + object.Width(style.width); + + // + style.Clean(); + } + + /** + * Apply Specified Style to Specified Object ... + * + * @param object: CChartObjectTrend, pointer reference of Object ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + */ + void ApplyTrendLineStyle( + CChartObjectTrend *&object, + ENUM_X_DIRECTION forDir // + ) + { + // + bool has = object != NULL; + if (!has) + { + return; + } + + // + if (!HasDirection(forDir)) + { + return; + } + + // + XPOIStyle style; + GetStyle(style, forDir); + + // + object.Color(style.clr); + object.Style(style.style); + object.Width(style.width); + + // + style.Clean(); + } + + // + // SPecial Draws Functions ... + + /** + * Draw Specified Pattern Pivot ... + * + * @param _pivot: XPivot, reference to Specified Pivot ... + * @param config: XPOIDrawConfig, Darwing Configuration ... + * @param thresholdMultiplier: int, pivot point threshold ... + */ + void DrawPivot( + XPivot &_pivot, + XPOIDrawConfig &config, + int thresholdMultiplier = 0 // + ) + { + // + // Normalize ... + thresholdMultiplier = NormalizeInt(thresholdMultiplier, 1); + + // + int arrowThreshold = config.arrowsThreshold * thresholdMultiplier; + arrowThreshold = NormalizeInt(arrowThreshold, 1); + + // + // Validate ... + bool has = _pivot.IsValid(); + if (!has) + { + return; + } + + // + XOHCL _bar; + has = _pivot.GetBar(_bar); + if (!has) + { + // + _bar.Clean(); + return; + } + + // + XCBarArrowObject *iObj; + has = DrawBarArrow( + _bar, + iObj, + _pivot.IsPeak() + ? config.arrowsPeakPriceType + : config.arrowsValePriceType, + _pivot.IsBullish() + ? config.bullishArrow + : config.bearishArrow, + _pivot.IsBullish() + ? config.bullishColor + : config.bearishColor, + config.arrowsWidth, + _pivot.IsBullish() + ? ANCHOR_TOP + : ANCHOR_BOTTOM, + _pivot.prefix + "_Pivot_" + ToXString(TimeToSeconds(_pivot.time)), + true, // Ignore Bar Tag ... + arrowThreshold // Threshold ... + ); + if (has) + { + drawnObjects.Add(iObj); + } + + // + ZeroMemory(iObj); + } + + /** + * Draw Specified Pattern Zone ... + * + * @param _zone: XBozxZone, reference to Specified Zone ... + * @param config: XPOIDrawConfig, Darwing Configuration ... + */ + void DrawZone( + XBoxZone &_zone, + XPOIDrawConfig &config // + ) + { + // + // Validate ... + bool has = _zone.IsValid(); + if (!has) + { + return; + } + + // + XCBoxObject *iObj; + has = DrawBox( + _zone, + iObj, + config.ignoreZonesAt, + _zone.type + "_Zone_" + ToXString(TimeToSeconds(_zone.from)) // + ); + if (has) + { + // + XPOIStyle iStyle; + GetBoxStyle( + iStyle, + _zone.dir // + ); + + // + iStyle.clr = + _zone.IsBullish() + ? config.bullishColor + : config.bearishColor; + iStyle.width = config.zonesWidth; + iStyle.style = config.zonesStyle; + + // + ApplyBoxStyle( + iObj, + iStyle // + ); + + // + drawnObjects.Add(iObj); + + // + iStyle.Clean(); + } + + // + ZeroMemory(iObj); + } + + /** + * Draw Specified Zones ... + * + * @param _zone: XBozxZone, reference to Collection Specified Zone ... + * @param config: XPOIDrawConfig, Darwing Configuration ... + */ + void DrawZones( + XBoxZone &_zones[], + XPOIDrawConfig &config // + ) + { + // + // Validate ... + bool has = HasChild(_zones); + if (!has) + { + return; + } + + // + for (int i = 0; i < ArraySize(_zones); i++) + { + // + DrawZone( + _zones[i], + config // + ); + } + } + + /** + * Draw Pivots ... + * + * @param pivots: XPivot, collection reference to Draw ... + * @param config: XPOIDrawConfig, reference to Specified Draw Style ... + */ + void DrawPivots( + XPivot &pivots[], + XPOIDrawConfig &config // + ) + { + // + // Validate ... + bool has = HasChild(pivots); + if (!has) + { + return; + } + + // + XPivot tmps[]; + int count = ArraySize(pivots); + for (int i = 0; i < count; i++) + { + // + XClean(tmps); + int sameCounts = ExtractSameTimePivots(pivots[i], tmps, pivots); + has = IsValidSize(sameCounts); + if (has) + { + // + for (int j = 0; j < sameCounts; j++) + { + DrawPivot(tmps[j], config, j + 1); + } + } + } + + // + // Cleanup ... + XClean(tmps); + } + + void DrawTrendLine( + string name, + double fromPrice, + datetime fromTime, + double toPrice, + datetime toTime, + XPOIDrawConfig &config, + color clr = CLR_NONE // + ) + { + // + // Validate ... + bool has = + IsXValid(name) && + IsXValid(toTime) && + IsXValid(fromTime) && + NotEmptyZero(toPrice) && + NotEmptyZero(fromPrice) && + fromTime < toTime; + if (!has) + { + return; + } + + // + ENUM_X_DIRECTION trendDir = + fromPrice > toPrice + ? X_DIRECTION_BEARISH + : fromPrice < toPrice + ? X_DIRECTION_BULLISH + : X_DIRECTION_NONE; + color clrTrend = + (clr != CLR_NONE) + ? clr + : IsXBullish(trendDir) + ? config.bullishColor + : config.bearishColor; + + // + CChartObjectTrend *object; + has = DrawTrendLine( + fromPrice, + fromTime, + toPrice, + toTime, + object, + name, + config.trendRayRight, + config.trendRayLeft // + ); + if (has) + { + // + // Apply Style ... + object.Color(clrTrend); + object.Width(config.trendWidth); + object.Style(config.trendStyle); + + // + // Save Object ... + drawnObjects.Add(object); + } + + // + ZeroMemory(object); + } + + void DrawTrendLine( + XTrend &trend, + XPOIDrawConfig &config, + color clr = CLR_NONE // + ) + { + // + // Validate ... + bool has = trend.IsValid(); + if (!has) + { + return; + } + + // + color trendColor = + (clr != CLR_NONE) + ? clr + : trend.IsBullish() + ? config.bullishColor + : trend.IsBearish() + ? config.bearishColor + : config.neuturalColor; + string name = trend.GetObjectID(); + + // + CChartObjectTrend *object; + has = DrawTrendLine( + trend.fromValue, + trend.fromTime, + trend.toValue, + trend.toTime, + object, + name, + config.trendRayRight, + config.trendRayLeft // + ); + if (has) + { + // + // Apply Style ... + object.Color(trendColor); + object.Width(config.trendWidth); + object.Style(config.trendStyle); + + // + // Save Object ... + drawnObjects.Add(object); + } + + // + ZeroMemory(object); + } + + /** + * Draw Specified Pattern info ... + * + * @param _bar: XOHCL, reference to Pattern's Bar ... + * @param _pivot: XPivot, reference to Pattern's Pivot ... + * @param _zone: XBoxZone, reference to Pattern's Zone ... + * @param _pattern: ENUM_X_BAR_PATTERN, Specified Bar Pattern ... + * @param _patternDir: ENUM_X_DIRECTION, Specified Bar Pattern's Direction ... + * @param thresholdMultiplier: int, pivot point threshold ... + * @param config: XPOIDrawConfig, Darwing Configuration ... + */ + void DrawPattern( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_BAR_PATTERN _pattern, + ENUM_X_DIRECTION _patternDir, + XPOIDrawConfig &config, + int thresholdMultiplier = 0 // + ) + { + // + // Validate ... + bool has = + _bar.IsValid() && + IsXValid(_pattern) && + HasDirection(_patternDir); + if (!has) + { + return; + } + + // + datetime cTime = TimeCurrent(); + + // + // Handle Draws ... + + // + // Draw OHCL Bar ... + + // + // Draw Pivot ... + DrawPivot(_pivot, config, thresholdMultiplier); + + // + // Draw Zone ... + _zone.to = cTime; + DrawZone(_zone, config); + } + + /** + * Draw Specified Bar Pattern Analysis ... + * + * @param analysis: XPatternAnalysis, reference to Specified Bar Pattern Analysis ... + * @param config: XPatternAnalysisDrawConfig, reference to Provide Drawing Configuration ... + */ + void DrawPatternAnalysis( + XPatternAnalysis &analysis, + XPatternAnalysisDrawConfig &config // + ) + { + // + bool has = analysis.IsValid(); + if (!has) + { + return; + } + + // + bool canDraw; + bool isBullish; + bool isBearish; + XOHCL patternBar; + bool canDrawZone; + bool canDrawPivot; + XPivot patternPivot; + XBoxZone patternBox; + ENUM_X_BAR_PATTERN pattern; + ENUM_X_DIRECTION patternDir; + + // + datetime cTime = TimeCurrent(); + int patternsPivotThresholdMultiplier = 0; + + // + // Support and Resistance ... + + // + // Support ... + isBearish = false; + isBullish = analysis.IsSupport(); + has = isBullish; + if (has) + { + // + pattern = X_BAR_PATTERN_SUPPORT; + patternDir = X_DIRECTION_BULLISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // Resistance ... + isBullish = false; + isBearish = analysis.IsResistance(); + has = isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_RESISTANCE; + patternDir = X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // PV: High and Low ... + + // + // Low ... + isBearish = false; + isBullish = analysis.IsLow(); + has = isBullish; + if (has) + { + // + pattern = X_BAR_PATTERN_LOW; + patternDir = X_DIRECTION_BULLISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // High ... + isBullish = false; + isBearish = analysis.IsHigh(); + has = isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_HIGH; + patternDir = X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // OB ... + isBullish = analysis.IsOB(X_DIRECTION_BULLISH); + isBearish = analysis.IsOB(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_OB; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // FVG ... + isBullish = analysis.IsFVG(X_DIRECTION_BULLISH); + isBearish = analysis.IsFVG(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_FVG; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // Momentum ... + isBullish = analysis.IsMomentum(X_DIRECTION_BULLISH); + isBearish = analysis.IsMomentum(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_MOMENTUM; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // Engulfed ... + isBullish = analysis.IsEngulfed(X_DIRECTION_BULLISH); + isBearish = analysis.IsEngulfed(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_ENGULFED; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // Pinned ... + isBullish = analysis.IsPinned(X_DIRECTION_BULLISH); + isBearish = analysis.IsPinned(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_PINNED; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // TrueGaped ... + isBullish = analysis.IsTrueGaped(X_DIRECTION_BULLISH); + isBearish = analysis.IsTrueGaped(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_TRUE_GAPED; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // Star ... + isBullish = analysis.IsStar(X_DIRECTION_BULLISH); + isBearish = analysis.IsStar(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_STAR; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // Piercing ... + isBullish = analysis.IsPiercing(X_DIRECTION_BULLISH); + isBearish = analysis.IsPiercing(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_PIERCING; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // Rising ... + isBullish = analysis.IsRising(X_DIRECTION_BULLISH); + isBearish = analysis.IsRising(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_RISING; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // Flag ... + isBullish = analysis.IsFlag(X_DIRECTION_BULLISH); + isBearish = analysis.IsFlag(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_FLAG; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // SignalKey ... + isBullish = analysis.IsSignalKey(X_DIRECTION_BULLISH); + isBearish = analysis.IsSignalKey(X_DIRECTION_BEARISH); + has = isBullish || isBearish; + if (has) + { + // + pattern = X_BAR_PATTERN_SIGNALKEY; + patternDir = + isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + canDraw = config.CanDraw(pattern); + if (canDraw) + { + // + has = analysis.GetPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir // + ); + if (has) + { + // + canDrawZone = config.CanDrawZone(pattern); + if (!canDrawZone) + { + patternBox.Clean(); + } + + // + canDrawPivot = config.CanDrawPivot(pattern); + if (!canDrawPivot) + { + patternPivot.Clean(); + } + else + { + patternsPivotThresholdMultiplier++; + } + + // + DrawPattern( + patternBar, + patternPivot, + patternBox, + pattern, + patternDir, + config.drawConfig, + patternsPivotThresholdMultiplier // + ); + } + } + } + + // + // Cleanup Resources ... + patternBar.Clean(); + patternBox.Clean(); + patternPivot.Clean(); + } + + /** + * Draw a Collection of Pattern Analysis ... + * + * @param analysises: XPatternAnalysis, collection reference to Data Source ... + * @param config: XPatternAnalysisDrawConfig, reference to Specified Drawing Config ... + */ + void DrawPatternAnalysises( + XPatternAnalysis &analysises[], + XPatternAnalysisDrawConfig &config // + ) + { + // + bool has = HasChild(analysises); + if (!has) + { + return; + } + + // + int count = ArraySize(analysises); + for (int i = 0; i < count; i++) + { + DrawPatternAnalysis(analysises[i], config); + } + } + + /** + * Draw Specified Pivots Analysis ... + * + * @param analysis: XPivotAnalysis, reference to Specified Pivot Analysis ... + * @param config: XPivotAnalysisDrawConfig, reference to Provide Drawing Configuration ... + */ + void DrawPivotAnalysis( + XPivotAnalysis &analysis, + XPivotAnalysisDrawConfig &config // + ) + { + // + bool has = analysis.IsValid(); + if (!has) + { + return; + } + + // + int count = 0; + XBoxZone tmpBox; + datetime cTime = TimeCurrent(); + + // + // Pivots ... + if (config.drawPivots) + { + // + has = analysis.HasPivots(); + if (has) + { + // + count = ArraySize(analysis.pivots); + for (int i = 0; i < count; i++) + { + // + DrawPivot( + analysis.pivots[i], + config.drawConfig // + ); + } + } + } + + // + // Support ... + if (config.drawSupport) + { + // + tmpBox.Clean(); + has = analysis.HasSupportBox(tmpBox); + if (has) + { + // + tmpBox.to = cTime; + DrawZone( + tmpBox, + config.drawConfig // + ); + } + } + + // + // Resistance ... + if (config.drawResistance) + { + // + tmpBox.Clean(); + has = analysis.HasResistanceBox(tmpBox); + if (has) + { + // + tmpBox.to = cTime; + DrawZone( + tmpBox, + config.drawConfig // + ); + } + } + + // + // Peak Trend ... + if (config.drawPeakTrend) + { + // + has = analysis.IsPeakAnalysed(); + if (has) + { + // + string iUpperName = analysis.GetUpperObjectID(); + CChartObjectTrend *iObj = new CChartObjectTrend(); + has = iObj.Create( + ChartIdentification(), + iUpperName, + SubWindowIdentification(), + analysis.fromTime, + analysis.peakFrom, + analysis.toTime, + analysis.peakTo // + ); + if (has) + { + // + // Styling ... + iObj.RayLeft(config.rayLeftTrends); + iObj.RayRight(config.rayRightTrends); + iObj.Width(config.drawConfig.zonesWidth); + iObj.Style(config.drawConfig.zonesStyle); + iObj.Color(IsXBullish(analysis.peakDir) + ? config.drawConfig.bullishColor + : config.drawConfig.bearishColor); + + // + // Storing ... + drawnObjects.Add(iObj); + } + } + } + + // + // Vale Trend ... + if (config.drawValeTrend) + { + // + has = analysis.IsValeAnalysed(); + if (has) + { + // + string iLowerName = analysis.GetLowerObjectID(); + CChartObjectTrend *iObj = new CChartObjectTrend(); + has = iObj.Create( + ChartIdentification(), + iLowerName, + SubWindowIdentification(), + analysis.fromTime, + analysis.valeFrom, + analysis.toTime, + analysis.valeTo // + ); + if (has) + { + // + // Styling ... + iObj.RayLeft(config.rayLeftTrends); + iObj.RayRight(config.rayRightTrends); + iObj.Width(config.drawConfig.zonesWidth); + iObj.Style(config.drawConfig.zonesStyle); + iObj.Color(IsXBullish(analysis.valeDir) + ? config.drawConfig.bullishColor + : config.drawConfig.bearishColor); + + // + // Storing ... + drawnObjects.Add(iObj); + } + } + } + + // + // Cleanup ... + tmpBox.Clean(); + + // + } + + protected: + // + + // + private: + // + + // + // Props ... + + // + string mPrefix; // Prefix of Created Objects ... + long mChartIdentification; // Chart Id ... + int mSubWindowIdentification; // Sub Window ... + + // +}; + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-position.drawer.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCPositionDrawer +// Description: Provides Position +// Drawing Tools ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-cobject.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" +#include "../Libraries/x-saherelm.x-pivot.analysis.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" + +// +// Definitions ... + +// +// Implementation ... + +class XCPositionDrawer : public XCBase +{ + // + // Public ... + public: + // + // Props ... + int window; // Window ID of Chart ... + ulong chartID; // Chart ID ... + XCTrade *trader; // XCTrade Instance ... + XPOIStyle riskStyle; // Risk Box Style ... + color inProfitColor; // In Profit Price Box Color ... + color inDrawdownColor; // In Drawdown Price Box Color ... + ENUM_LINE_STYLE priceStyle; // Price Box Style ... + XPOIStyle rewardStyle; // Reward Box Style ... + CArrayObj positionObjects; // Drawn Positions Object Instances Collection ... + CArrayObj finalizedObjects; // Finalized Drawn Positions Object Instances Collection ... + + // + // Constructor ... + XCPositionDrawer( + XCTrade *_trader, + ulong _chartID = 0, + int _window = 0 // + ) : XCBase() + { + // + Init( + _trader, + _chartID, + _window // + ); + } + + // + // Deconstructor ... + ~XCPositionDrawer() + { + Destroy(); + } + + // + // Tools ... + + /** + * Initialize Class Instance ... + * + * @param _trader: XCTrade, reference Pointer to Trader Instance Class ... + * @param _chartID: ulong, Specified Chart ID ... + * @param _window: int, Specified Chart Window ID ... + */ + void Init( + XCTrade *_trader, + ulong _chartID = 0, + int _window = 0 // + ) + { + // + // Validate ... + bool has = + _window >= 0 && + _chartID >= 0 && + _trader != NULL; + if (!has) + { + return; + } + + // + trader = _trader; + window = _window; + chartID = _chartID; + + // + // Prepare Default Styles ... + + // + // Risk Style ... + riskStyle.width = 1; + riskStyle.fill = false; + riskStyle.clr = clrRed; + riskStyle.style = STYLE_DASH; + + // + // Reward Style ... + rewardStyle.width = 1; + rewardStyle.fill = false; + rewardStyle.clr = clrLime; + rewardStyle.style = STYLE_DASH; + + // + // Price Style ... + priceStyle = STYLE_SOLID; + inProfitColor = clrAqua; // ApplyAlpha(clrAqua, 100); + inDrawdownColor = clrMagenta; // ApplyAlpha(clrMagenta, 100); + } + + /** + * Destroy Instance ... + */ + void Destroy() + { + // + riskStyle.Clean(); + rewardStyle.Clean(); + // positionObjects + // finalizedObjects + } + + /** + * Validate Instance ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + trader != NULL; + + // + return result; + } + + /** + * Update Positions ... + * + * @param barIndex: int, Specified Bar Index ... + */ + void Update(int barIndex = 0) + { + // + // Normalize ... + barIndex = NormalizeInt(barIndex, 0); + + // + // Validate ... + bool has = IsValid(); + if (!has) + { + return; + } + + // + // Update Exists Positions ... + XPosition positions[]; + int positionsCount = trader.GetPositions(positions); + has = IsValidSize(positionsCount); + if (has) + { + // + int drawingsCount = positionObjects.Total(); + has = IsValidSize(drawingsCount); + if (has) + { + // + for (int i = 0; i < positionsCount; i++) + { + // + for (int j = 0; j < drawingsCount; j++) + { + // + // Check Object is Belong to Position ... + has = ((XCPositionObject *)positionObjects.At(j)).IsBelong(positions[i]); + if (has) + { + // + // Update Position Object ... + has = ((XCPositionObject *)positionObjects.At(j)).Update(positions[i]); + } + } + } + } + } + + // + // Update Test Positions ... + positionsCount = positionObjects.Total(); + has = + !HasChild(positions) && + IsValidSize(positionsCount); + if (has) + { + // + XPosition iPosition; + for (int i = 0; i < positionsCount; i++) + { + // + // Retrieve Position from Object ... + has = ((XCPositionObject *)positionObjects.At(i)).GetPosition(iPosition); + if (has) + { + // + // Manully Update Position ... + has = ((XCPositionObject *)positionObjects.At(i)).Update(barIndex); + } + } + + // + iPosition.Clean(); + } + } + + // + // Trade Event Handlers ... + + /** + * Add Executed Signal ... + * + * @param signal: XSignal, reference to Executed Signal ... + */ + void AddExecutedSignal(XSignal &signal) + { + // + // Validate ... + bool has = + signal.IsValid() && + signal.IsExecuted(); + if (!has) + { + return; + } + + // + XPosition iPosition; + + // + // Check Position Exists ... + has = trader.GetPosition( + signal.positionId, + iPosition // + ); + // + // Initial by Testing Position ... + if (!has) + { + // + has = ToXPosition( + signal, + iPosition, + trader.GetMagicNumber(), + signal.positionId // + ); + } + + // + // Validate result ... + if (has) + { + // + XCPositionObject *iObj = new XCPositionObject(); + has = iObj.Create( + chartID, + window, + iPosition // + ); + if (has) + { + // + // Set Stylers to Position ... + iObj.riskStyle = riskStyle; + iObj.priceStyle = priceStyle; + iObj.rewardStyle = rewardStyle; + iObj.inProfitColor = inProfitColor; + iObj.inDrawdownColor = inDrawdownColor; + + // + // Add to Collection ... + positionObjects.Add(iObj); + } + } + + // + // Cleanup Resources ... + iPosition.Clean(); + } + + /** + * Handle Stop Loss Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleStopLossTriggered(const XDeal &deal) + { + // + Finalize(deal.positionId); + } + + /** + * Handle Take Profit Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleOnTakeProfitTriggered(const XDeal &deal) + { + Finalize(deal.positionId); + } + + /** + * Handle Position Force Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param position: XPosition instance refrence, Triggered Position ... + * @param comment: string, Comment ... + */ + void HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + Finalize(ticket); + } + + /** + * Handle Position Modified Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ + void HandleOnPositionModified( + const ulong ticket, + const double profit, + const string comment // + ) + { + // + // Detect Position Index ... + int index = FindIndex(ticket); + bool has = IsValidIndex(index); + if (!has) + { + return; + } + + // + // Get Position of Objects ... + XPosition _position; + has = ((XCPositionObject *)positionObjects.At(index)).GetPosition(_position); + if (has) + { + // + // Get Position of Trader Instance ... + has = trader.GetPosition( + ticket, + _position // + ); + if (has) + { + // + // Update Position ... + ((XCPositionObject *)positionObjects.At(index)).Update(_position); + } + } + + // + // Cleanup Resources ... + _position.Clean(); + } + + // + // Protected ... + protected: + // + + /** + * Finalize Specified Position ... + * Remove it From Position Objects and add it to Finalized Objects Cllection ... + * + * @param ticket: ulong, Specified Position Ticket ... + */ + void Finalize(ulong ticket) + { + // + int index = FindIndex(ticket); + bool has = IsValidIndex(index); + if (!has) + { + return; + } + + // + // XCPositionObject *iObj = positionObjects.At(index); + // positionObjects.Delete(index); + // finalizedObjects.Add(iObj); + } + + /** + * Find Specified Position Index ... + * + * @param ticket: ulong, Specified Position Ticket ... + * + * @return ( int ) + */ + int FindIndex(ulong ticket) + { + // + int result = -1; + + // + // Validate ... + int count = + NotEmptyZero(ticket) && + positionObjects.Total(); + bool has = IsValidSize(count); + if (!has) + { + return result; + } + + // + XPosition iPosition; + for (int i = 0; i < count; i++) + { + // + has = ((XCPositionObject *)positionObjects.At(i)).GetPosition(iPosition); + has = has && + iPosition.ticket == ticket; + if (has) + { + // + result = i; + break; + } + } + + // + // Cleanup Resources ... + iPosition.Clean(); + + // + return result; + } + + // + // Private ... + private: + // + + // +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-restrictions.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCRestrictions +// Description: provides all Requirements for Apply Restrictions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// #region Definitions ... +// +// Awailable Restrictions Period ... +enum ENUM_X_TRADE_RESTRICTIONS_PERIOD +{ + X_TRADE_RESTRICATION_NONE, // None + X_TRADE_RESTRICATION_HOURLY, // Per Hour + X_TRADE_RESTRICATION_DAILY, // Per Day + X_TRADE_RESTRICATION_WEEKLY, // Per Week + X_TRADE_RESTRICATION_MONTHLY, // Per Month +}; + +// #region Extensions ... +// +// Converts to String ... +string ToXString(ENUM_X_TRADE_RESTRICTIONS_PERIOD value) +{ + // + string result = NULL; + + // + result = EnumToString(value); + + // + return result; +} + +// +// Check Has Restrictions or not ... +bool HasXRestrictions(ENUM_X_TRADE_RESTRICTIONS_PERIOD value) +{ + // + bool result = false; + + // + result = value != X_TRADE_RESTRICATION_NONE; + + // + return result; +} + +/** + * Get Restrictions Period Delay in Seconds ... + * + * @param value: ENUM_X_TRADE_RESTRICTIONS_PERIOD ... + * + * @return ( int ) + */ +int RestrictionsPeriodSeconds(ENUM_X_TRADE_RESTRICTIONS_PERIOD value) +{ + // + int result = 0; + + // + // Check Restrictions is Valid or not ... + if (!HasXRestrictions(value)) + { + return result; + } + + // + switch (value) + { + // + default: + case X_TRADE_RESTRICATION_NONE: + result = 0; + break; + + // + case X_TRADE_RESTRICATION_HOURLY: + result = PeriodSeconds(PERIOD_H1); + break; + + // + case X_TRADE_RESTRICATION_DAILY: + result = PeriodSeconds(PERIOD_D1); + break; + + // + case X_TRADE_RESTRICATION_WEEKLY: + result = PeriodSeconds(PERIOD_W1); + break; + + // + case X_TRADE_RESTRICATION_MONTHLY: + result = PeriodSeconds(PERIOD_MN1); + break; + } + + // + return result; +} + +/** + * Calculate Restrictions End Time ... + * + * @param value: ENUM_X_TRADE_RESTRICTIONS_PERIOD ... + * @param multiplier: int, Restrictions Period Multiplier ... + * @param fromTime: Restrictions Starts Time ... + * + * @return ( datetime ) + */ +datetime RestrictionsEndTime( + ENUM_X_TRADE_RESTRICTIONS_PERIOD value, + int multiplier = 1, + datetime fromTime = NULL // +) +{ + // + datetime result = NULL; + + // + // Normalize Multiplier ... + if (multiplier < 1) + { + multiplier = 1; + } + if (!IsXValid(fromTime)) + { + fromTime = TimeCurrent(); + } + + // + // Calculate Requirements ... + int periodSeconds = RestrictionsPeriodSeconds(value); + int timeInSeconds = (int)fromTime + (periodSeconds * multiplier); + MqlDateTime timeStruct; + bool hasStruct = TimeToStruct( + (datetime)timeInSeconds, + timeStruct // + ); + if (hasStruct) + { + // + timeStruct.min = 0; + timeStruct.sec = 0; + + // + result = StructToTime(timeStruct); + } + else + { + result = (datetime)timeInSeconds; + } + + // + ZeroMemory(timeStruct); + + // + return result; +} +// #endregion + +// #region Event Handler Types ... +typedef void (*TRestrictionEvent)(); +// #endregion +// #endregion + +// +// Implementation ... +class XCRestrictions : public XCBase +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructor ... + XCRestrictions() + { + // + Clean(); + Default(); + } + + // + // Deconstructor ... + ~XCRestrictions() + { + // + Clean(); + } + + // #region Properties ... + // #region RestrictionsPeriod ... + /** + * Get Restrictions Period ... + * + * @return ( ENUM_X_TRADE_RESTRICTIONS_PERIOD ) + */ + ENUM_X_TRADE_RESTRICTIONS_PERIOD GetRestrictionsPeriod() + { + return mRestrictionsPeriod; + } + + /** + * Get Restrictions Period ... + * + * @param value: ENUM_X_TRADE_RESTRICTIONS_PERIOD + */ + void SetRestrictionsPeriod(ENUM_X_TRADE_RESTRICTIONS_PERIOD value) + { + mRestrictionsPeriod = value; + } + // #endregion + + // #region Restrictions Period Multiplier ... + /** + * Get Restrictions Period Multiplier ... + * + * @return ( int ) + */ + int GetRestrictionsPeriodMultiplier() + { + return mRestrictionsPeriodMultiplier; + } + + /** + * Set Restrictions Period Multiplier ... + * + * @param value: int ... + */ + void SetRestrictionsPeriodMultiplier(int value) + { + // + if (value < 1) + { + value = 1; + } + + // + mRestrictionsPeriodMultiplier = value; + } + // #endregion + + // #region Signals ... + /** + * Get Issued Signals ... + * + * @return ( int ) + */ + int GetSignals() + { + return mSignals; + } + + /** + * Get Issued Long Signals ... + * + * @return ( int ) + */ + int GetLongSignals() + { + return mLongSignals; + } + + /** + * Issued Short Signals ... + * + * @return ( int ) + */ + int GetShortSignals() + { + return mShortSignals; + } + + /** + * Get Issued Signals in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedSignals() + { + return mRestrictedSignals; + } + + /** + * Get Issued Long Signals in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedLongSignals() + { + return mRestrictedLongSignals; + } + + /** + * Get Issued Short Signals in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedShortSignals() + { + return mRestrictedShortSignals; + } + + /** + * Get Allowed Signals in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedSignalsInRestrictions() + { + return mAllowedSignalsInRestrictions; + } + + /** + * Set Allowed Signals in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedSignalsInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedSignalsInRestrictions = value; + } + + /** + * Get Allowed Long Signals in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedLongSignalsInRestrictions() + { + return mAllowedLongSignalsInRestrictions; + } + + /** + * Set Allowed Long Signals in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedLongSignalsInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedLongSignalsInRestrictions = value; + } + + /** + * Get Allowed Short Signals in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedShortSignalsInRestrictions() + { + return mAllowedShortSignalsInRestrictions; + } + + /** + * Set Allowed Short Signals in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedShortSignalsInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedShortSignalsInRestrictions = value; + } + // #endregion + + // #region Trades ... + /** + * Executed Trades ... + * + * @return ( int ) + */ + int GetTrades() + { + return mTrades; + } + + /** + * Executed Long Trades ... + * + * @return ( int ) + */ + int GetLongTrades() + { + return mLongTrades; + } + + /** + * Executed Short Trades ... + * + * @return ( int ) + */ + int GetShortTrades() + { + return mShortTrades; + } + + /** + * Executed Trades in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedTrades() + { + return mRestrictedTrades; + } + + /** + * Executed Long Trades in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedLongTrades() + { + return mRestrictedLongTrades; + } + + /** + * Executed Short Trades in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedShortTrades() + { + return mRestrictedShortTrades; + } + + /** + * Get Allowed Trades in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedTradesInRestrictions() + { + return mAllowedTradesInRestrictions; + } + + /** + * Set Allowed Trades in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedTradesInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedTradesInRestrictions = value; + } + + /** + * Get Allowed Long Trades in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedLongTradesInRestrictions() + { + return mAllowedLongTradesInRestrictions; + } + + /** + * Set Allowed Long Trades in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedLongTradesInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedLongTradesInRestrictions = value; + } + + /** + * Get Allowed Short Trades in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedShortTradesInRestrictions() + { + return mAllowedShortTradesInRestrictions; + } + + /** + * Set Allowed Short Trades in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedShortTradesInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedShortTradesInRestrictions = value; + } + // #endregion + + // #region Wins ... + /** + * Touched Wins ... + * + * @return ( int ) + */ + int GetWins() + { + return mWins; + } + + /** + * Touched Long Wins ... + * + * @return ( int ) + */ + int GetLongWins() + { + return mLongWins; + } + + /** + * Touched Short Wins ... + * + * @return ( int ) + */ + int GetShortWins() + { + return mShortWins; + } + + /** + * Touched Wins in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedWins() + { + return mRestrictedWins; + } + + /** + * Touched Long Wins in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedLongWins() + { + return mRestrictedLongWins; + } + + /** + * Touched Short Wins in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedShortWins() + { + return mRestrictedShortWins; + } + + /** + * Get Allowed Wins in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedWinsInRestrictions() + { + return mAllowedWinsInRestrictions; + } + + /** + * Set Allowed Wins in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedWinsInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedWinsInRestrictions = value; + } + + /** + * Get Allowed Long Wins in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedLongWinsInRestrictions() + { + return mAllowedLongWinsInRestrictions; + } + + /** + * Set Allowed Long Wins in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedLongWinsInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedLongWinsInRestrictions = value; + } + + /** + * Get Allowed Short Wins in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedShortWinsInRestrictions() + { + return mAllowedShortWinsInRestrictions; + } + + /** + * Set Allowed Short Wins in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedShortWinsInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedShortWinsInRestrictions = value; + } + // #endregion + + // #region Losess ... + /** + * Touched Loses ... + * + * @return ( int ) + */ + int GetLoses() + { + return mLoses; + } + + /** + * Touched Long Loses ... + * + * @return ( int ) + */ + int GetLongLoses() + { + return mLongLoses; + } + + /** + * Touched Short Loses ... + * + * @return ( int ) + */ + int GetShortLoses() + { + return mShortLoses; + } + + /** + * Touched Loses in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedLoses() + { + return mRestrictedLoses; + } + + /** + * Touched Long Loses in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedLongLoses() + { + return mRestrictedLongLoses; + } + + /** + * Touched Short Loses in Restrictions Period ... + * + * @return ( int ) + */ + int GetRestrictedShortLoses() + { + return mRestrictedShortLoses; + } + + /** + * Get Allowed Loses in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedLosesInRestrictions() + { + return mAllowedLosesInRestrictions; + } + + /** + * Set Allowed Loses in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedLosesInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedLosesInRestrictions = value; + } + + /** + * Get Allowed Long Loses in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedLongLosesInRestrictions() + { + return mAllowedLongLosesInRestrictions; + } + + /** + * Set Allowed Long Loses in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedLongLosesInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedLongLosesInRestrictions = value; + } + + /** + * Get Allowed Short Loses in Restrictions Period ... + * + * @return ( int ) + */ + int GetAllowedShortLosesInRestrictions() + { + return mAllowedShortLosesInRestrictions; + } + + /** + * Set Allowed Short Loses in Restrictions Period ... + * + * @param value: int ... + */ + void SetAllowedShortLosesInRestrictions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mAllowedShortLosesInRestrictions = value; + } + // #endregion + + // #region Current Restrictions ... + /** + * Get Current Restrictions End Time ... + * + * @return ( datetime ) + */ + datetime GetCurrentRestrictionsEnd() + { + return mRestrictionsEnd; + } + + /** + * Get Current Restrictions Start Time ... + * + * @return ( datetime ) + */ + datetime GetCurrentRestrictionsStart() + { + return mRestrictionsStart; + } + // #endregion + // #endregion + + // #region Tools ... + /** + * Check Restrictions Exists or not ... + * + * @return ( bool ) + */ + bool HasRestrictions() + { + // + bool result = false; + + // + result = + HasXRestrictions(mRestrictionsPeriod); + + // + return result; + } + + /** + * Handle Signal Issued ... + * + * @param signal: XSignal ... + */ + void HandleSignal(XSignal &signal) + { + // + if (!signal.IsValid()) + { + return; + } + + // + bool isLong = IsLong(signal.type); + + // + mSignals++; + + // + if (isLong) + { + mLongSignals++; + } + else + { + mShortSignals++; + } + + // + if (HasRestrictions()) + { + // + mRestrictedSignals++; + + // + if (isLong) + { + mRestrictedLongSignals++; + } + else + { + mRestrictedShortSignals++; + } + } + } + + /** + * Handle Signal Execution ... + * + * @param signal: XSignal ... + */ + void HandleTrade(XSignal &signal) + { + // + if (!signal.IsValid()) + { + return; + } + bool isLong = IsLong(signal.type); + + // + mTrades++; + + // + if (isLong) + { + mLongTrades++; + } + else + { + mShortTrades++; + } + + // + if (HasRestrictions()) + { + // + mRestrictedTrades++; + + // + if (isLong) + { + mRestrictedLongTrades++; + } + else + { + mRestrictedShortTrades++; + } + } + } + + /** + * Handle Trade Win ... + * + * @param type: ENUM_X_POSITION_TYPES ... + */ + void HandleTradeWin(ENUM_X_POSITION_TYPES type) + { + // + if (!IsXValid(type)) + { + return; + } + bool isLong = IsLong(type); + + // + mWins++; + + // + if (isLong) + { + mLongWins++; + } + else + { + mShortWins++; + } + + // + if (HasRestrictions()) + { + // + mRestrictedWins++; + + // + if (isLong) + { + mRestrictedLongWins++; + } + else + { + mRestrictedShortWins++; + } + } + } + + /** + * Handle Trade Lose ... + * + * @param type: ENUM_X_POSITION_TYPES ... + */ + void HandleTradeLose(ENUM_X_POSITION_TYPES type) + { + // + if (!IsXValid(type)) + { + return; + } + bool isLong = IsLong(type); + + // + mLoses++; + + // + if (isLong) + { + mLongLoses++; + } + else + { + mShortLoses++; + } + + // + if (HasRestrictions()) + { + // + mRestrictedLoses++; + + // + if (isLong) + { + mRestrictedLongLoses++; + } + else + { + mRestrictedShortLoses++; + } + } + } + + /** + * Check Allow Issue Signal or not ... + * + * @param signal: XSignal ... + * + * @return ( bool ) + */ + bool CheckAllowIssueSignal(XSignal &signal) + { + // + bool result = false; + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + return result; + } + bool isLong = IsLong(signal.type); + + // + // Check if Restrictions Exists ... + if (!HasRestrictions()) + { + return result; + } + + // + // Check Signal Restrictions ... + if (result) + { + // + if (IsValidSize(mAllowedSignalsInRestrictions)) + { + // + result = + result && + mRestrictedLongSignals < mAllowedSignalsInRestrictions; + } + } + + // + // Check Long Signal Restrictions ... + if (result) + { + // + if (isLong && + IsValidSize(mAllowedLongSignalsInRestrictions)) + { + // + result = + result && + mRestrictedLongSignals < mAllowedLongSignalsInRestrictions; + } + } + + // + // Check Short Signal Restrictions ... + if (result) + { + // + if (!isLong && + IsValidSize(mAllowedShortSignalsInRestrictions)) + { + // + result = + result && + mRestrictedShortSignals < mAllowedShortSignalsInRestrictions; + } + } + + // + return result; + } + + /** + * Check Allow Issue Signal or not ... + * + * @param signal: XSignal ... + * + * @return ( bool ) + */ + int CheckAllowExecuteSignal(XSignal &signal) + { + // + bool result = false; + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + return result; + } + bool isLong = IsLong(signal.type); + + // + // Check if Restrictions Exists ... + if (!HasRestrictions()) + { + return result; + } + + // + // Check Trade Restrictions ... + if (result) + { + // + if (IsValidSize(mAllowedTradesInRestrictions)) + { + // + result = + result && + mRestrictedTrades < mAllowedTradesInRestrictions; + } + } + + // + // Check Long Trade Restrictions ... + if (result) + { + // + if (IsValidSize(mAllowedLongTradesInRestrictions)) + { + // + result = + result && + mRestrictedLongTrades < mAllowedLongTradesInRestrictions; + } + } + + // + // Check Short Trade Restrictions ... + if (result) + { + // + if (IsValidSize(mAllowedShortTradesInRestrictions)) + { + // + result = + result && + mRestrictedShortTrades < mAllowedShortTradesInRestrictions; + } + } + + // + // Check Wins Restrictions ... + if (result) + { + // + if (IsValidSize(mAllowedWinsInRestrictions)) + { + // + result = + result && + mRestrictedWins < mAllowedWinsInRestrictions; + } + } + + // + // Check Long Wins Restriction ... + if (result) + { + // + if (IsValidSize(mAllowedLongWinsInRestrictions)) + { + // + result = + result && + mRestrictedLongWins < mAllowedLongWinsInRestrictions; + } + } + + // + // Check Short Wins Restriction ... + if (result) + { + // + if (IsValidSize(mAllowedShortWinsInRestrictions)) + { + // + result = + result && + mRestrictedShortWins < mAllowedShortWinsInRestrictions; + } + } + + // + // Check Lose Restrictions ... + if (result) + { + // + if (IsValidSize(mAllowedLosesInRestrictions)) + { + // + result = + result && + mRestrictedLoses < mAllowedLosesInRestrictions; + } + } + + // + // Check Long Lose Restrictions ... + if (result) + { + // + if (IsValidSize(mAllowedLongLosesInRestrictions)) + { + // + result = + result && + mRestrictedLongLoses < mAllowedLongLosesInRestrictions; + } + } + + // + // Check Short Lose Restrictions ... + if (result) + { + // + if (IsValidSize(mAllowedShortLosesInRestrictions)) + { + // + result = + result && + mRestrictedShortLoses < mAllowedShortLosesInRestrictions; + } + } + + // + return result; + } + // #endregion + + // #region Event Handlers Registrations ... + /** + * Register Restrictions Start Event Handler ... + * + * @param handler: TRestrictionEvent ... + */ + void AddRestrictionsStartEventHandler(TRestrictionEvent handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add(handler, mOnRestrictionsStartEventHandlers); + } + + /** + * Register Restrictions End Event Handler ... + * + * @param handler: TRestrictionEvent ... + */ + void AddRestrictionsEndEventHandler(TRestrictionEvent handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add(handler, mOnRestrictionsEndEventHandlers); + } + // #endregion + + /** + * Process Ticks for Restrictions ... + * Applied Eac Secconds ... + */ + void Process() + { + // + // Check Restrictions Exists or not ... + if (!HasRestrictions()) + { + return; + } + + // + // Calculate Requirements ... + datetime currentTime = TimeCurrent(); + + // + // Check Current Restrictions Exists or not ... + // Initial Restrictions Period if not Exists ... + if (!IsXValid(mRestrictionsStart)) + { + // + // Initial Restrictions ... + mRestrictionsStart = currentTime; + mRestrictionsEnd = RestrictionsEndTime( + mRestrictionsPeriod, + mRestrictionsPeriodMultiplier, + mRestrictionsStart // + ); + + // + // Loging Restrictions Start ... + LogRestrictionsStart(); + + // + // Notfy Restrictions Start Event Handlers ... + NotifyRestrictionsStartEventHandlers(); + + // + return; + } + + // + // Validate Current Restrictions ... + + // + // Check Process Exists or not ... + if (IsXValid(mLastCheck)) + { + // + // Validate New Check Must Happens after 1 Minute ... + bool canCheck = currentTime >= mLastCheck + 60; + if (!canCheck) + { + return; + } + } + + // + // Update Last Check ... + mLastCheck = currentTime; + + // + // Check Restrictions End ... + bool isEnded = currentTime >= mRestrictionsEnd; + if (isEnded) + { + // + // Fire Restrictions End Event Handlers ... + NotifyRestrictionsEndEventHandlers(); + + // + // Logging Resrtrictions Summary if Required ... + LogRestrictionsEnd(); + + // + // Reset Restrictions ... + ResetRestrictions(); + + // + return; + } + + // + // TODO: Implement What we want if necessary ... + } + + // + // Protected ... + protected: + // + // Props ... + + /** + * Cleanup ... + */ + void Clean() + { + // + mAllowedWinsInRestrictions = 0; + mAllowedLongWinsInRestrictions = 0; + mAllowedShortWinsInRestrictions = 0; + + // + mAllowedLosesInRestrictions = 0; + mAllowedLongLosesInRestrictions = 0; + mAllowedShortLosesInRestrictions = 0; + + // + mAllowedSignalsInRestrictions = 0; + mAllowedLongSignalsInRestrictions = 0; + mAllowedShortSignalsInRestrictions = 0; + + // + mAllowedTradesInRestrictions = 0; + mAllowedLongTradesInRestrictions = 0; + mAllowedShortTradesInRestrictions = 0; + + // + ResetRestrictions(); + XClean(mOnRestrictionsEndEventHandlers); + XClean(mOnRestrictionsStartEventHandlers); + } + + /** + * Set Default Values ... + */ + void Default() + { + // + mRestrictionsPeriodMultiplier = 1; + mRestrictionsPeriod = X_TRADE_RESTRICATION_NONE; + } + + /** + * Logging Restrictions Start Summary ... + */ + void LogRestrictionsStart() + { + } + + /** + * Logging Restrictions End Summary ... + */ + void LogRestrictionsEnd() + { + } + + // #region Event Handlers Notifier ... + /** + * Notify Registered Restrictions Start Event Handlers ... + */ + void NotifyRestrictionsStartEventHandlers() + { + // + int count = ArraySize(mOnRestrictionsStartEventHandlers); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + mOnRestrictionsStartEventHandlers[i](); + } + } + + /** + * Notify Registered Restrictions End Event Handlers ... + */ + void NotifyRestrictionsEndEventHandlers() + { + // + int count = ArraySize(mOnRestrictionsEndEventHandlers); + if (!IsValidSize(count)) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + mOnRestrictionsEndEventHandlers[i](); + } + } + // #endregion + + // #region Restrictions Summary Cleaners ... + /** + * Reset all Restricted Counters ... + */ + void ResetRestrictions() + { + // + mRestrictionsEnd = NULL; + mRestrictionsStart = NULL; + + // + ResetTradeRestrictions(); + ResetSignalRestrictions(); + ResetTradeWinRestrictions(); + ResetTradeLoseRestrictions(); + } + + /** + * Resetting Signal Restrictions ... + */ + void ResetSignalRestrictions() + { + // + mRestrictedSignals = 0; + mRestrictedLongSignals = 0; + mRestrictedShortSignals = 0; + } + + /** + * Resetting Trade Restrictions ... + */ + void ResetTradeRestrictions() + { + // + mRestrictedTrades = 0; + mRestrictedLongTrades = 0; + mRestrictedShortTrades = 0; + } + + /** + * Resetting Trade Win Restrictions ... + */ + void ResetTradeWinRestrictions() + { + mWins = 0; + mLongWins = 0; + mShortWins = 0; + } + + /** + * Resetting Trade Lose Restrictions ... + */ + void ResetTradeLoseRestrictions() + { + // + mLoses = 0; + mLongLoses = 0; + mShortLoses = 0; + } + // #endregion ... + + // + // Private ... + private: + // + // Props ... + + // + // Last Restrictions Time ... + datetime mLastCheck; // Last Restrictions Check ... + datetime mRestrictionsEnd; // Last Restrictions End Time ... + datetime mRestrictionsStart; // Last Restrictions Start Time ... + + // + // Restrictions Period ... + int mRestrictionsPeriodMultiplier; // Restrictions Period Multiplier ... + ENUM_X_TRADE_RESTRICTIONS_PERIOD mRestrictionsPeriod; // Restrictions Period ... + + // #region Signals ... + // + int mSignals; // Issued Signals ... + int mLongSignals; // Issued Long Signals ... + int mShortSignals; // Issued Short Signals ... + + // + int mRestrictedSignals; // Issued Signals in Restrictions Period ... + int mRestrictedLongSignals; // Issued Long Signals in Restrictions Period ... + int mRestrictedShortSignals; // Issued Short Signals in Restrictions Period ... + + // + int mAllowedSignalsInRestrictions; // Allowed Signals in Restrictions Period ... + int mAllowedLongSignalsInRestrictions; // Allowed Long Signals in Restrictions Period ... + int mAllowedShortSignalsInRestrictions; // Allowed Short Signals in Restrictions Period ... + // #endregion + + // #region Trades ... + // + int mTrades; // Executed Trades ... + int mLongTrades; // Executed Long Trades ... + int mShortTrades; // Executed Short Trades ... + + // + int mRestrictedTrades; // Executed Trades in Restrictions Period ... + int mRestrictedLongTrades; // Executed Long Trades in Restrictions Period ... + int mRestrictedShortTrades; // Executed Short Trades in Restrictions Period ... + + // + int mAllowedTradesInRestrictions; // Allowed Trades in Restrictions Period ... + int mAllowedLongTradesInRestrictions; // Allowed Long Trades in Restrictions Period ... + int mAllowedShortTradesInRestrictions; // Allowed Short Trades in Restrictions Period ... + // #endregion + + // #region Wins ... + // + int mWins; // Touched Wins ... + int mLongWins; // Touched Long Wins ... + int mShortWins; // Touched Short Wins ... + + // + int mRestrictedWins; // Touched Wins in Restrictions Period ... + int mRestrictedLongWins; // Touched Long Wins in Restrictions Period ... + int mRestrictedShortWins; // Touched Short Wins in Restrictions Period ... + + // + int mAllowedWinsInRestrictions; // Allowed Wins in Restrictions Period ... + int mAllowedLongWinsInRestrictions; // Allowed Long Wins in Restrictions Period ... + int mAllowedShortWinsInRestrictions; // Allowed Short Wins in Restrictions Period ... + // #endregion + + // #region Losess ... + // + int mLoses; // Touched Loses ... + int mLongLoses; // Touched Long Loses ... + int mShortLoses; // Touched Short Loses ... + + // + int mRestrictedLoses; // Touched Loses in Restrictions Period ... + int mRestrictedLongLoses; // Touched Long Loses in Restrictions Period ... + int mRestrictedShortLoses; // Touched Short Loses in Restrictions Period ... + + // + int mAllowedLosesInRestrictions; // Allowed Loses in Restrictions Period ... + int mAllowedLongLosesInRestrictions; // Allowed Long Loses in Restrictions Period ... + int mAllowedShortLosesInRestrictions; // Allowed Short Loses in Restrictions Period ... + // #endregion + + // #region Event Handlers ... + TRestrictionEvent mOnRestrictionsEndEventHandlers[]; // Restrictions End Event Handlers ... + TRestrictionEvent mOnRestrictionsStartEventHandlers[]; // Restrictions Start Event Hnadlers ... + // #endregion +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-rm.panel.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCRMPanel +// Description: provides all based classes for use ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-app-dialog.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" + +// +#include +#include +#include +#include +#include +#include + +// +// Implementation ... + +// +class XCRMPanel : public XCAppDialog +{ + // + public: + // + // Event Binding ... + // EVENT_MAP_BEGIN(XCRMPanel) + // ON_EVENT(ON_CLICK, btnBuy, HandleBtnBuyClicked) + // ON_EVENT(ON_CLICK, btnSell, HandleBtnSellClicked) + // EVENT_MAP_END(XCRMPanel) + + // + // Constructor(s) ... + XCRMPanel() + { + // + Default(); + } + + // + // Deconstructor ... + ~XCRMPanel() + { + // + HandleRemoveObjects(); + + // + ZeroMemory(mTrader); + } + + // + // Props ... + + // + int SubWindow() + { + return subWindow; + } + + // + void SubWindow(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + subWindow = value; + } + + // + // BUY ... + + // + string BtnBuyLabel() + { + return buyLabelStr; + } + + // + void BtnBuyLabel(string value) + { + buyLabelStr = value; + } + + // + color BtnBuyBGColor() + { + return btnBuyBGColor; + } + + // + void BtnBuyBGColor(color value) + { + btnBuyBGColor = value; + } + + // + // SELL ... + + // + string BtnSellLabel() + { + return sellLabelStr; + } + + // + void BtnSellLabel(string value) + { + sellLabelStr = value; + } + + // + color BtnSellBGColor() + { + return btnSellBGColor; + } + + // + void BtnSellBGColor(color value) + { + btnSellBGColor = value; + } + + // + double RiskPercent() + { + return riskPercent; + } + + // + void RiskPercent(double value) + { + // + if (value < minAllowedRiskPercent) + { + value = minAllowedRiskPercent; + } + + // + if (value > maxAllowedRiskPercent) + { + value = maxAllowedRiskPercent; + } + + // + riskPercent = value; + + // + tbRisk.Text((string)value); + } + + // + // + // + + bool HasSL() + { + return slLine != NULL; + } + + double ReadSL() + { + // + double result = 0; + + // + if (HasSL()) + { + // + result = slLine.GetDouble(OBJPROP_PRICE); + result = NormalizePrice(result, _Symbol); + } + + // + return result; + } + + bool HasTP() + { + return tpLine != NULL; + } + + double ReadTP() + { + // + double result = 0; + + // + if (HasTP()) + { + // + result = tpLine.GetDouble(OBJPROP_PRICE); + result = NormalizePrice(result, _Symbol); + } + + // + return result; + } + + bool HasEntry() + { + return entryLine != NULL; + } + + double ReadEntry() + { + // + double result = 0; + + // + if (HasEntry()) + { + // + result = entryLine.GetDouble(OBJPROP_PRICE); + result = NormalizePrice(result, _Symbol); + } + + // + return result; + } + + bool GetDirection(ENUM_X_DIRECTION &dir) + { + // + bool result = false; + + // + dir = X_DIRECTION_NONE; + + // + result = HasTP() && + HasSL() && + HasEntry(); + + // + if (!result) + { + return result; + } + + // + double sl = ReadSL(); + double tp = ReadTP(); + double entry = ReadEntry(); + + // + result = sl > 0 && + tp > 0 && + entry > 0; + if (!result) + { + return result; + } + + // + bool isBullish = + tp > entry && + tp > sl && + entry > sl; + bool isBearish = + tp < entry && + tp < sl && + entry < sl; + result = isBullish || + isBearish; + if (!result) + { + return result; + } + + // + dir = isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + // + // Tools ... + + // + void Default() + { + // + string prefix = CreateInstanceId(); + + // + defaultR2R = 2; + riskPercent = 1; + defaultRisk = 50; + minAllowedRiskPercent = 0.5; + maxAllowedRiskPercent = 10.0; + + // + disabledBtnColor = clrLightGray; + disabledBtnBGColor = clrGray; + + // + tbRiskID = prefix + "_RiskTB"; + + // + buyLabelStr = "Buy"; + btnBuyBGColor = clrLime; + btnBuyColor = clrDarkBlue; + btnBuyID = prefix + "_" + buyLabelStr; + + // + sellLabelStr = "Sell"; + btnSellBGColor = clrRed; + btnSellColor = clrDarkBlue; + btnSellID = prefix + "_" + sellLabelStr; + + // + slLine = NULL; + slColor = clrMagenta; + slID = prefix + "_SL"; + + // + tpLine = NULL; + tpColor = clrAqua; + tpID = prefix + "_TP"; + + // + entryLine = NULL; + entryColor = clrYellow; + entryID = prefix + "_Entry"; + + // + btnDrawRemoveID = prefix + "_DrawRemove"; + drawLabelStr = "Draw"; + removeLabelStr = "Remove"; + btnDrawColor = clrWhite; + btnDrawBGColor = clrDarkBlue; + btnRemoveColor = clrYellow; + btnRemoveBGColor = clrDarkRed; + + // + slippage = 10; + magicNumber = 1694056; + + // + // Create Trader Instance and Configure it ... + mTrader = new XCTrade( + slippage, + magicNumber // + ); + } + + // + void UpdateState() + { + // + bool canEnable = HasSL() && + HasTP() && + HasEntry(); + + // + if (canEnable) + { + SetRemoveMode(); + } + else + { + SetDrawMode(); + } + + // + double entry = GetBid(_Symbol); + ENUM_X_DIRECTION dir; + if (GetDirection(dir)) + { + entry = GetEntry(_Symbol, dir); + } + + // + if (HasEntry()) + { + double iEntry = ReadEntry(); + if (iEntry != entry) + { + SetEntry(entry); + } + } + } + + // + // Handlers ... + + /** + * Handle Btn Buy Clicked ... + */ + void HandleBtnBuyClicked() + { + // + ENUM_X_DIRECTION dir; + bool has = GetDirection(dir); + bool isBullish = has & + IsBullish(dir); + if (!has || !isBullish) + { + return; + } + + // + double tp = ReadTP(); + double sl = ReadSL(); + double entry = ReadEntry(); + + // + mTrader.Buy( + _Symbol, + _Period, + volume, + entry, + sl, + tp // + ); + } + + /** + * Handle Btn Sell Clicked ... + */ + void HandleBtnSellClicked() + { + // + ENUM_X_DIRECTION dir; + bool has = GetDirection(dir); + bool isBearish = has & + IsBearish(dir); + if (!has || !isBearish) + { + return; + } + + // + double tp = ReadTP(); + double sl = ReadSL(); + double entry = ReadEntry(); + + // + mTrader.Sell( + _Symbol, + _Period, + volume, + entry, + sl, + tp // + ); + } + + /** + * Handle Draw Remove Position ... + */ + void HandleBtnDrawRemoveClicked() + { + // + string btnText = btnDrawRemove.Text(); + if (btnText == drawLabelStr) + { + HandleDrawObjects(); + } + else if (btnText == removeLabelStr) + { + HandleRemoveObjects(); + } + } + + /** + * Handle Risk Percent Changed ... + */ + void HandleOnRiskPercentChanged() + { + // + string tbRiskStr = tbRisk.Text(); + + // + double tbNewRisk = (double)tbRiskStr; + RiskPercent(tbNewRisk); + } + + // + // Virtuals ... + + // + virtual bool OnEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // + ) + { + // + bool result = false; + + // + XCAppDialog::OnEvent(id, lparam, dparam, sparam); + + // + // Check if the event is a button click + if (id == ON_CLICK + CHARTEVENT_CUSTOM) + { + // + // Verify if the clicked object is this button + if (lparam == btnBuy.Id()) + { + // + HandleBtnBuyClicked(); + result = true; + } + else if (lparam == btnSell.Id()) + { + // + HandleBtnSellClicked(); + result = true; + } + else if (lparam == btnDrawRemove.Id()) + { + // + HandleBtnDrawRemoveClicked(); + result = true; + } + } + else if (id == ON_END_EDIT + CHARTEVENT_CUSTOM) + { + // + if (lparam == tbRisk.Id()) + { + // + HandleOnRiskPercentChanged(); + result = true; + } + } + else if (id == CHARTEVENT_OBJECT_DRAG) + { + // + if (sparam == entryLine.Name()) + { + // + CalculateData(); + result = true; + } + else if (sparam == tpLine.Name()) + { + // + CalculateData(); + result = true; + } + else if (sparam == slLine.Name()) + { + // + CalculateData(); + result = true; + } + } + + // + return result; + } + + // + // Overrides ... + + // + bool Create( + const long chart, + const string name, + const int subwin, + const int x1, + const int y1, + const int x2, + const int y2 // + ) + { + // + bool result = false; + + // + // Create App Dialog instance it Self ... + result = XCAppDialog::Create( + chart, + name, + subwin, + x1, + y1, + x2, + y2 // + ); + if (!result) + { + return result; + } + + // + chartId = chart; + subWindow = subwin; + + // + // Configure Dialog ... + BackgroundColor(clrBlack); + + // + int top = Top(); + int left = Left(); + int right = Right(); + int bottom = Bottom(); + + // + int width = Width(); + int height = Height(); + + // + int desiredWidth = width - left; + int desiredHeight = height - top; + + // + int btnWidth = desiredWidth / 2; + int btnHeight = desiredHeight / 3; + + // + // Risk Edit ... + int tbRiskX1 = 0; + int tbRiskY1 = 0; + int tbRiskX2 = tbRiskX1 + (btnWidth * 2); + int tbRiskY2 = tbRiskY1 + btnHeight; + result = tbRisk.Create( + chart, + tbRiskID, + subWindow, + tbRiskX1, + tbRiskY1, + tbRiskX2, + tbRiskY2 // + ); + if (!result) + { + return result; + } + + // + result = tbRisk.Text((string)riskPercent); + result = tbRisk.TextAlign(ALIGN_CENTER); + + // + result = Add(tbRisk); + + // + // Create Draw/Remove Button ... + int btnDrawX1 = 0; + int btnDrawY1 = desiredHeight - (btnHeight * 2); + int btnDrawX2 = btnDrawX1 + (btnWidth * 2); + int btnDrawY2 = btnDrawY1 + btnHeight; + result = btnDrawRemove.Create( + chart, + btnDrawRemoveID, + subWindow, + btnDrawX1, + btnDrawY1, + btnDrawX2, + btnDrawY2 // + ); + if (!result) + { + return result; + } + + // + result = btnDrawRemove.Text(drawLabelStr); + result = btnDrawRemove.Color(btnDrawColor); + result = btnDrawRemove.ColorBackground(btnDrawBGColor); + + // + result = Add(btnDrawRemove); + + // + // Create Buy Button ... + int btnBuyX1 = 0; + int btnBuyY1 = desiredHeight - btnHeight; + int btnBuyX2 = btnBuyX1 + btnWidth; + int btnBuyY2 = btnBuyY1 + btnHeight; + result = btnBuy.Create( + chart, + btnBuyID, + subWindow, + btnBuyX1, + btnBuyY1, + btnBuyX2, + btnBuyY2 // + ); + if (!result) + { + return result; + } + + // + result = btnBuy.Text(buyLabelStr); + result = btnBuy.Color(btnBuyColor); + result = btnBuy.ColorBackground(btnBuyBGColor); + + // + result = Add(btnBuy); + + // + // Create Sell Button ... + int btnSellX1 = btnBuyX2; + int btnSellY1 = btnBuyY1; + int btnSellX2 = btnSellX1 + btnWidth; + int btnSellY2 = btnSellY1 + btnHeight; + result = btnSell.Create( + chart, + btnSellID, + subWindow, + btnSellX1, + btnSellY1, + btnSellX2, + btnSellY2 // + ); + if (!result) + { + return result; + } + + // + result = btnSell.Text(sellLabelStr); + result = btnSell.Color(btnSellColor); + result = btnSell.ColorBackground(btnSellBGColor); + + // + result = Add(btnSell); + + // + if (result) + { + // + UpdateState(); + CalculateData(); + } + + // + return result; + } + + // + protected: + // + XCTrade *mTrader; + int slippage; + long magicNumber; + + // + long chartId; + int subWindow; + + // + string slID; + color slColor; + CChartObjectHLine *slLine; + + // + string tpID; + color tpColor; + CChartObjectHLine *tpLine; + + // + string entryID; + color entryColor; + CChartObjectHLine *entryLine; + + // + double riskPercent; + double minAllowedRiskPercent; + double maxAllowedRiskPercent; + + // + double volume; + + // + double defaultR2R; + double defaultRisk; + + // + color disabledBtnColor; + color disabledBtnBGColor; + + // + // Risk Percent Edit ... + CEdit tbRisk; + string tbRiskID; + + // + // BUY Button ... + CButton btnBuy; + string btnBuyID; + string buyLabelStr; + color btnBuyColor; + color btnBuyBGColor; + + // + // SELL Button ... + CButton btnSell; + string btnSellID; + string sellLabelStr; + color btnSellColor; + color btnSellBGColor; + + // + // DRAW / REMOVE Button ... + CButton btnDrawRemove; + string btnDrawRemoveID; + string drawLabelStr; + string removeLabelStr; + color btnDrawColor; + color btnDrawBGColor; + color btnRemoveColor; + color btnRemoveBGColor; + + // + private: + // + + bool EnableBuy(bool value) + { + // + bool result = false; + + // + btnBuy.Locking(!value); + btnSell.Pressed(value); + if (!value) + { + // + // Disabled ... + btnBuy.Color(disabledBtnColor); + btnBuy.ColorBackground(disabledBtnBGColor); + } + else + { + // + // Enable ... + btnBuy.Color(btnBuyColor); + btnBuy.ColorBackground(btnBuyBGColor); + } + + // + return result; + } + + bool EnableSell(bool value) + { + // + bool result = false; + + // + btnSell.Locking(!value); + btnSell.Pressed(value); + if (!value) + { + // + // Disabled ... + btnSell.Color(disabledBtnColor); + btnSell.ColorBackground(disabledBtnBGColor); + } + else + { + // + // Enable ... + btnSell.Color(btnSellColor); + btnSell.ColorBackground(btnSellBGColor); + } + + // + return result; + } + + bool SetDrawMode() + { + // + bool result = false; + + // + result = btnDrawRemove.Text(drawLabelStr); + result = btnDrawRemove.Color(btnDrawColor); + result = btnDrawRemove.ColorBackground(btnDrawBGColor); + + // + return result; + } + + bool SetRemoveMode() + { + // + bool result = false; + + // + result = btnDrawRemove.Text(removeLabelStr); + result = btnDrawRemove.Color(btnRemoveColor); + result = btnDrawRemove.ColorBackground(btnRemoveBGColor); + + // + return result; + } + + void HandleDrawObjects() + { + // + double entry = GetBid(_Symbol); + double points = GetPoints(_Symbol); + double riskRatio = defaultRisk * points; + double rewardRatio = riskRatio * defaultR2R; + double sl = entry - riskRatio; + double tp = entry + rewardRatio; + + // + datetime rectTime1 = iTime( + _Symbol, + _Period, + 20 // + ); + datetime rectTime2 = iTime( + _Symbol, + _Period, + 19 // + ); + + // + bool has = false; + + // + // Create Entry Line ... + entryLine = new CChartObjectHLine(); + has = entryLine.Create( + chartId, + entryID, + subWindow, + entry // + ); + if (!has) + { + // + HandleRemoveObjects(); + return; + } + entryLine.Selectable(false); + entryLine.Color(entryColor); + + // + // Create SL Line ... + slLine = new CChartObjectHLine(); + has = slLine.Create( + chartId, + slID, + subWindow, + sl // + ); + if (!has) + { + // + HandleRemoveObjects(); + return; + } + slLine.Color(slColor); + slLine.Selectable(true); + + // + // Create TP Line ... + tpLine = new CChartObjectHLine(); + has = tpLine.Create( + chartId, + tpID, + subWindow, + tp // + ); + if (!has) + { + // + HandleRemoveObjects(); + return; + } + tpLine.Color(tpColor); + tpLine.Selectable(true); + + // + CalculateData(); + } + + void HandleRemoveObjects() + { + // + if (HasSL()) + { + // + slLine.Delete(); + slLine.Detach(); + ZeroMemory(slLine); + } + + // + if (HasTP()) + { + // + tpLine.Delete(); + tpLine.Detach(); + ZeroMemory(tpLine); + } + + // + if (HasEntry()) + { + // + entryLine.Delete(); + entryLine.Detach(); + ZeroMemory(entryLine); + } + + // + UpdateState(); + CalculateData(); + } + + void CalculateData() + { + // + EnableBuy(false); + EnableSell(false); + + // + ENUM_X_DIRECTION dir; + bool has = GetDirection(dir); + if (!has) + { + return; + } + + // + bool isBullish = IsBullish(dir); + bool isBearish = IsBearish(dir); + + // + if (isBullish) + { + // + EnableBuy(true); + EnableSell(false); + } + else if (isBearish) + { + // + EnableSell(true); + EnableBuy(false); + } + + // + double sl = ReadSL(); + double tp = ReadTP(); + double entry = ReadEntry(); + double points = GetPoints(_Symbol); + + // + double risk = MathAbs(entry - sl); + int riskPoints = (int)(risk / points); + double riskRewardRatio = MathAbs(tp - entry) / risk; + riskRewardRatio = NormalizeDouble(riskRewardRatio, 2); + + // + double balance = GetBalance(); + + // + double riskAmount = riskPercent * (balance / 100); + riskAmount = NormalizePrice(riskAmount, _Symbol); + + // + double rewardAmount = riskAmount * riskRewardRatio; + rewardAmount = NormalizePrice(rewardAmount, _Symbol); + + // + string currency = mTrader.mAccount.GetCurrency(); + + // + volume = mTrader + .mAccount + .CalculateVolume( + _Symbol, + riskAmount, + riskPoints // + ); + volume = NormalizeVolume(volume, _Symbol); + + // + string slDesc = "SL: " + ToXString(sl) + + ", Risk: " + ToXString(riskPoints) + " pt (" + ToXString(riskPercent) + "%)" + + ", Amount: " + ToXString(riskAmount) + currency; + slLine.Tooltip(slDesc); + slLine.Description(slDesc); + + // + string tpDesc = "TP: " + ToXString(tp) + " (" + ToXString(rewardAmount) + " " + currency + ")" + + ", R2R: 1:" + ToXString(riskRewardRatio); + tpLine.Tooltip(tpDesc); + tpLine.Description(tpDesc); + + // + string entryDesc = "Entry: " + ToXString(entry) + + ", Volume: " + ToXString(volume); + entryLine.Tooltip(entryDesc); + entryLine.Description(entryDesc); + + // + } + + void SetEntry(double value) + { + // + if (value <= 0 || + !HasEntry()) + { + return; + } + + // + bool has = entryLine + .SetDouble(OBJPROP_PRICE, value); + } + + double GetBalance() + { + // + double result = 0; + + // + // TODO: Change This ... + return mTrader.mAccount.GetBalance(); + + // + return result; + } + + // +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-signaller.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class +// ------------------------------------------------- +// Name: XCBaseSignaller ... +// Description: Base Signaller Class ... +// +// - Create an Instance based on this ... +// - Attach Required Helpers for Indicator Usages ... +// - Override Virtual Methdos: +// - [] ProcessTick: Processing All Ticks +// - [] ProcessNewBar: Processing All New Bars +// - [] CheckForGuard: Check For Guards +// - [] NormalizeSignal: Normalizing Prepared Signal ... +// - [] CheckAdditionslSignallerValidations: Additional Class Validations +// +// - Dont Forget to Call OnSignal Event in Process Methods when +// a signal Appears ... +// +// - also Whenever you want you can call PrepareSignal Action to +// provide a Signal based on Current Market State ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm Base Signaller Class" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-market.pattern.class.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// +// Definitions ... + +// +// Implementations ... +class XCBaseSignaller : public XCBase +{ + // + // Public ... + public: + // + // Props ... + string name; // Name ... + string symbol; // Symbol ... + ENUM_TIMEFRAMES period; // Period ... + + // + bool ignoreTargets; // Ignore Signal Targets ... + double slAdditionDistance; // SL Addition Distance ... + double maxAllowedRiskDistance; // Max Allowed Risk In Points ... + + // + // Restrictions ... + datetime restUntil; // Resting Time ... + int restingSignals; // Resting Signals ... + datetime lastSignalAt; // Holding Last Signal's Time ... + int restingDelay; // Resting Bars After Last Signal ... + int loosingTrades; // Loosing Trades ... + + // + TCanAnalyse canAnalyseEventListener; + + // + XCMarketPatternDetector *patternDetector; + + // + // Constructor ... + XCBaseSignaller( + string _name, // Name ... + string _symbol, // Symbol ... + ENUM_TIMEFRAMES _period, // Period ... + bool _processAllTicks = false, // Process All Ticks ... + double _defaultSignalR2R = 1.5, // Default Signal Risk To Reward Ratio ... + double _defaultSignalRiskInPoint = 50, // Default Signal Risk In Point ... + double _defaultSignalVolume = 0.01 // Default Signal Volume ... + ) + { + // + // Assign Properties ... + name = _name; + symbol = _symbol; + period = _period; + + // + ignoreTargets = false; + slAdditionDistance = 0; + maxAllowedRiskDistance = 0; + + // + processAllTicks = _processAllTicks; + defaultSignalR2R = _defaultSignalR2R; + defaultSignalVolume = _defaultSignalVolume; + defaultSignalRiskInPoint = _defaultSignalRiskInPoint; + + // + // Normalize ... + defaultSignalR2R = NormalizeDouble(defaultSignalR2R, 1, 10); + defaultSignalVolume = NormalizeDouble(defaultSignalVolume, 0.01); + defaultSignalVolume = NormalizeVolume(defaultSignalVolume, symbol, 2); + defaultSignalRiskInPoint = NormalizeDouble(defaultSignalRiskInPoint, 10); + + // + // Set Dfault Values ... + mProcessedTicksCount = 0; + mLastCheckedBarTime = NULL; + + // + patternDetector = new XCMarketPatternDetector(); + } + + // + // Deconstructor ... + ~XCBaseSignaller() + { + // + // Cleanup Event Listeners ... + SpecifiedClean(onSignalEventListeners); + + // + delete patternDetector; + ZeroMemory(patternDetector); + } + + // + // Event Listeners ... + + /** + * Add On Signal Event Listener ... + * + * @param listener: TOnSignal instance ... + */ + void AddOnSignalEventHandler(TOnSignal listener) + { + // + // Validate ... + if (listener == NULL) + { + return; + } + + // + Add( + listener, + onSignalEventListeners // + ); + } + + // + // Actions ... + + /** + * Check Signaller Validation ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsSpecifiedValid(name) && + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + // + patternDetector != NULL && + // + CheckAdditionslSignallerValidations() + // + ; + + // + return result; + } + + /** + * Handling On Tick Event ... + * + * @param barIndex: int, Specified Bar Index ... + */ + void OnTick(int barIndex = 0) + { + // + // Normalize Bar Index ... + if (barIndex < 0) + { + barIndex = 0; + } + + // + // Define Requirements ... + XOHCL iBar; + bool has = false; + bool isNewBar = false; + + // + // Get Current Bar Time ... + datetime cBarTime = GetBarTime( + symbol, + period, + barIndex // + ); + + // + // Validate Bar Time ... + has = IsSpecifiedValid(cBarTime); + if (!has) + { + return; + } + + // + // Check Rest Until ... + has = !IsXValid(restUntil) || (IsXValid(restUntil) && cBarTime > restUntil); + if (!has) + { + return; + } + + // + // Check Process Permissions ... + has = CanAnalyseMarket(cBarTime); + if (!has) + { + return; + } + + // + // Check if new Bar, Reset Processed Ticks Count ... + isNewBar = cBarTime > mLastCheckedBarTime; + if (isNewBar) + { + // + mProcessedTicksCount = 0; + ProcessNewBar(barIndex); + return; + } + + // + // Check Allow Process ... + // Process All Ticks ... + // Process New Bars ... + has = processAllTicks || + (!processAllTicks && isNewBar); + if (!has) + { + return; + } + + // + // Set Last Works ... + mProcessedTicksCount++; + mLastCheckedBarTime = cBarTime; + + // + ProcessTick(barIndex); + } + + // + // Virtuals ... + + /** + * Processing Tick ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessTick(int barIndex = 0) + { + } + + /** + * Processing New Bar ... + * + * @param barIndex: int, Specified Bar Index ... + */ + virtual void ProcessNewBar(int barIndex = 0) + { + } + + /** + * Check Guards Based on MarketConditions ... + * + * @param guards: XGuard, reference collection to holds result ... + * @param positions: XPosition, reference collection to provides positions ... + * @param barIndex: int + * + * @return ( int ) + */ + int virtual CheckForGuard( + XGuard &guards[], + XPosition &positions[], + int barIndex = 0 // + ) + { + // + int result = 0; + + // + SpecifiedClean(guards); + + // + result = ArraySize(guards); + + // + return result; + } + + /** + * Check Additional Validations on Childs Instances ... + * + * @return ( bool virtual ) + */ + bool virtual CheckAdditionslSignallerValidations() + { + return true; + } + + /** + * Normalizing Signal by Signaller Custom Props ... + * + * @param signal: XSignal ... + */ + void virtual NormalizeSignal(XSignal &signal) + { + } + + /** + * Prepare Restrictions Update For Losing Trades ... + */ + void LoseTrade() + { + // + restingSignals++; + loosingTrades++; + } + + /** + * Prepare Restrictions For Winning Trades ... + */ + void WinTrade() + { + // + if (loosingTrades > 0) + { + loosingTrades--; + } + + // + if (restingSignals > 0) + { + restingSignals--; + } + } + + // + // Protected ... + protected: + // + // Props ... + + // + bool processAllTicks; // Specified Processing All Ticks or not ... + + // + int mProcessedTicksCount; // Prcoessed Ticks Count ... + datetime mLastCheckedBarTime; // Last Checked Bar Time ... + + // + double defaultSignalR2R; // Default Signal Risk To Reward Ratio ... + double defaultSignalVolume; // Default Signal Volume ... + double defaultSignalRiskInPoint; // Default Signal Risk In Point ... + + // + // Event Notifiers ... + + /** + * Notify OnSignal Event Listeners ... + * + * @param signal: XSignal, Specified Signal to Notify ... + */ + void NotifySignalEventListeners(XSignal &signal) + { + // + int count = ArraySize(onSignalEventListeners); + + // + // Validate ... + if (!IsValidSize(count) || !signal.IsValid()) + { + return; + } + + // + // Check Restrictions ... + if (HasRestrictions()) + { + // + bool ignore = HandleRestrictions(signal); + if (ignore) + { + return; + } + } + + // + // Do Notify ... + for (int i = 0; i < count; i++) + { + onSignalEventListeners[i](signal); + } + + // + lastSignalAt = signal.time; + } + + /** + * Calling Can Analyse Event Listeners ... + * Check Can Analayse Market or not ... + * + * @param time: datetime, Specified Time for Checking ... + * + * @return ( bool ) + */ + bool CanAnalyseMarket(datetime time = NULL) + { + // + bool result = false; + + // + // Normalize ... + time = NormalizeTime(time); + + // + // Validation ... + result = IsValid(); + if (!result) + { + return result; + } + + // + result = canAnalyseEventListener == NULL; + if (result) + { + return result; + } + + // + // Calling Can Analyse Event Listener ... + result = canAnalyseEventListener( + symbol, + period, + time // + ); + + // + return result; + } + + /** + * Preparing Default Signal ... + * + * @param signal: XSignal, holding result Signal ... + * @param forDir: ENUM_X_DIRECTION + * @param targets: XTarget Array, Provides Signal Targets (Price) ... + * @param r2r: double, Provides Signal (r2r), if not Provided uses Default R2R ... + * @param slPrice: double, Provides Signal SL Price, if not Provided uses riskInPoint ... + * @param riskInPoint: double, Provides Signal Risk Amount which Multiplied to Points, if not Provided uses DefaultRiskInPoint ... + * + * @return ( bool ) + */ + bool PrepareSignal( + XSignal &signal, + ENUM_X_DIRECTION forDir, + XTarget &targets[], // + double r2r = 0, + double slPrice = 0, + double riskInPoint = 0 // + ) + { + // + bool result = false; + + // + // Prepare ... + signal.Clean(); + + // + // Normalize ... + + // + // Validate ... + result = IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsSpecifiedBullish(forDir); + + // + double point = GetPoints(symbol); + double spread = GetSpread(symbol); + double volume = defaultSignalVolume; + double entry = GetEntry(symbol, forDir); + + // + riskInPoint = riskInPoint > 0 && slPrice <= 0 + ? riskInPoint + : defaultSignalRiskInPoint; + double risk = (riskInPoint * point); + risk = slPrice > 0 + ? MathAbs(entry - slPrice) + : risk; + + // + r2r = r2r > 0 + ? r2r + : defaultSignalR2R; + double reward = (risk * r2r) + spread; + + // + double tp = + isBullish + ? entry + reward + : entry - reward; + + // + double sl = + isBullish + ? entry - risk + : entry + risk; + + // + // Filling Values ... + signal.tp = tp; + signal.sl = sl; + signal.entry = entry; + signal.provider = name; + signal.symbol = symbol; + signal.period = period; + signal.volume = volume; + signal.time = TimeCurrent(); + signal.type = + isBullish + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + signal.mode = X_ORDER_MODE_MARKET; + + // + // Apply Targets ... + if (HasChild(targets)) + { + // + ApplyTargetsOnSignal( + forDir, + targets, + signal // + ); + } + + // + // Validate Signal ... + result = signal.IsValid(); + if (result) + { + // + NormalizeSignal(signal); + result = signal.IsValid(); + } + + // + if (!result) + { + signal.Clean(); + } + + // + return result; + } + + /** + * Check Signaller Has Restrictions or not ... + * + * @return ( bool ) + */ + bool HasRestrictions() + { + // + bool result = false; + + // + result = + // + // Rest Delay ... + restingDelay > 0 || + // + // Resting Signals ... + restingSignals > 0 || + // + // Rest Until ... + IsXValid(restUntil) + // + ; + + // + return result; + } + + /** + * Handle Restrictions On Signal ... + * + * @param signal: XSignal, reference to Provided Sginal ... + * + * @return ( bool ) + */ + bool HandleRestrictions(XSignal &signal) + { + // + // Ignore Signal Execution ... + bool result = true; + + // + // Check Restrictions Exists ... + if (!HasRestrictions()) + { + // + // Disable Signal Ignoring and Allow Notify Signal ... + result = false; + return result; + } + + // + datetime cTime = TimeCurrent(); + + // + // Resting Signals ... + if (restingSignals > 0) + { + // + restingSignals--; + return result; + } + + // + // Rest Until ... + if (IsXValid(restUntil)) + { + // + if (cTime > restUntil) + { + // + restUntil = NULL; + + // + // Disable Signal Ignoring and Allow Notify Signal ... + result = false; + return result; + } + else + { + // + // Ignore Signal ... + return result; + } + } + + // + // Resting Delay ... + if (restingDelay > 0 && + IsXValid(lastSignalAt)) + { + // + int lastSignalIDX = GetBarIndex( + signal.symbol, + signal.period, + lastSignalAt // + ); + if (IsValidIndex(lastSignalIDX)) + { + // + if (lastSignalIDX > restingDelay) + { + // + restingDelay = 0; + // + // Disable Signal Ignoring and Allow Notify Signal ... + result = false; + return result; + } + else + { + // + // Ignore Signal ... + return result; + } + } + } + + // + return result; + } + + /** + * Reset All Restrictions ... + */ + void ResetRestrictions() + { + // + restingDelay = 0; + restUntil = NULL; + restingSignals = 0; + } + + // + // Private ... + private: + // + // Props ... + + // + // Event Listeners ... + TOnSignal onSignalEventListeners[]; +}; + +// + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-target.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XCTarget +// Description: provides all Positions Target requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" + +// +// Implementation ... +class XCTarget : public XCBase +{ + // + // Public ... + public: + // + XCTrade *trader; + XCAlert *alert; + XSignal signals[]; + + // + // Constructor ... + XCTarget( + XCTrade *_trader, // + XCAlert *_alert // + ) : XCBase() + { + // + alert = _alert; + trader = _trader; + + // + XClean(signals); + } + + // + // Deconstructor ... + ~XCTarget() + { + Destroy(); + } + + // + void Destroy() + { + // + XClean(signals); + } + + // + // Actions ... + + /** + * Manage Positions ... + * + * @param barIndex: int, Bar Index ... + */ + void Manage(int barIndex = 0) + { + // + // Normalize ... + barIndex = NormalizeInt(barIndex, 0); + + // + // Extract In Profit Positions ... + XPosition positions[]; + int count = GetInProfitPositions(positions); + bool has = IsValidIndex(count); + if (!has) + { + return; + } + + // + XSignal iSignal; + XTarget iTarget; + int signalIDX = -1; + int targetIDX = -1; + XPosition iPosition; + + // + // Loop through Positions ... + for (int i = 0; i < count; i++) + { + // + // Select Positions ... + iPosition = positions[i]; + has = FindSignal( + signalIDX, + iPosition.ticket // + ); + if (!has) + { + continue; + } + iSignal = signals[signalIDX]; + + // + // Selecting Target ... + targetIDX = iSignal.appliedTargetIDX; + if (iSignal.isTargetApplied) + { + targetIDX++; + } + + // + // Validate Targets Size ... + has = HasChild(iSignal.targets) && + targetIDX < ArraySize(iSignal.targets); + if (has) + { + // + // Select Target ... + iTarget = iSignal.targets[targetIDX]; + + // + // Check Can Apply Target and Apply it ... + has = HandleApplyTarget(iTarget, iPosition); + if (has) + { + // + // Update Target IDX ... + iSignal.appliedTargetIDX++; + } + } + + // + // Update Signal ... + signals[signalIDX] = iSignal; + + // + // Cleanup ... + iSignal.Clean(); + iTarget.Clean(); + iPosition.Clean(); + } + + // + // Cleanup Resources ... + iSignal.Clean(); + iTarget.Clean(); + iPosition.Clean(); + } + + /** + * Extract in Profit Positions ... + * + * @param positions: XPosition, reference collection to holds result ... + * + * @return ( int ) + */ + int GetInProfitPositions( + XPosition &positions[] // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(positions); + + // + // Validate ... + if (trader == NULL) + { + return result; + } + + // + result = trader.GetInProfitPositions( + positions, + NULL, // All Symbols ... + NULL, // All Providers ... + NULL, // All Periods ... + NULL, // All Position Types ... + X_POSITION_SELECT_ALL, // Select Method ... + true, // Filter by Magic ... + true // Force Clean ... + ); + if (IsValidSize(result)) + { + // + XPosition iPos; + XPosition tmp[]; + Copy( + positions, + tmp // + ); + XClean(positions); + while (HasChild(tmp)) + { + // + iPos = tmp[0]; + ArrayRemove( + tmp, + 0, + 1 // + ); + + // + int idx = -1; + bool has = FindSignal( + idx, + iPos.ticket // + ); + if (has) + { + // + AddRef( + iPos, + positions // + ); + } + } + + // + XClean(tmp); + iPos.Clean(); + + // + result = ArraySize(positions); + } + + // + return result; + } + + /** + * Add Executed Signal ... + * + * @param signal: XSignal, reference to Executed Signal ... + */ + void AddExecutedSignal(XSignal &signal) + { + // + // Validate ... + if (!signal.IsValid() || !signal.IsExecuted()) + { + return; + } + + // + AddRef( + signal, + signals // + ); + } + + // + // Trade Event Handlers ... + + /** + * Handle Stop Loss Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleOnStopLossTriggered(const XDeal &deal) + { + RemoveSignal(deal.positionId); + } + + /** + * Handle Take Profit Event Triggered ... + * + * @param deal: XDeal instance refrence, provides Triggered Deal info ... + */ + void HandleOnTakeProfitTriggered(const XDeal &deal) + { + RemoveSignal(deal.positionId); + } + + /** + * Handle Position Force Closed Event ... + * + * @param ticket: ulong, triggered Positions ticket ... + * @param position: XPosition instance refrence, Triggered Position ... + * @param comment: string, Comment ... + */ + void HandleOnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // + ) + { + RemoveSignal(ticket); + } + + // + // Event Handlers Registration ... + + // + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mStopLossEventHandlers + // + ); + } + + // + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTakeProfitEventHandlers + // + ); + } + + // + void AddOnForceClosePositionEventHandler(TOnForceClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnForceCloseEventHandlers + // + ); + } + + // + // Protected ... + protected: + // + + /** + * Find Specified Signal ... + * + * @param index: int, reference to holds detected index ... + * @param signal: XSignal, reference to Specified Signal ... + * + * @return ( bool ) + */ + bool FindSignal( + int &index, + XSignal &signal // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Validate ... + result = signal.IsValid() && + HasChild(signals); + if (!result) + { + return result; + } + + // + // Looping Through Signals ... + int count = ArraySize(signals); + for (int i = 0; i < count; i++) + { + // + result = signals[i] + .IsSameAs(signal); + if (result) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + /** + * Find Specified Signal ... + * + * @param index: int, reference to holds detected index ... + * @param ticket: ulong, Specified Signal Position ID ... + * + * @return ( bool ) + */ + bool FindSignal( + int &index, + ulong ticket // + ) + { + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Validate ... + result = NotEmptyZero(ticket) && + HasChild(signals); + if (!result) + { + return result; + } + + // + // Looping Through Signals ... + int count = ArraySize(signals); + for (int i = 0; i < count; i++) + { + // + result = signals[i].IsValid() && + signals[i].IsExecuted() && + signals[i].positionId == ticket; + if (result) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; + } + + /** + * Remove Specified Signal ... + * + * @param ticket: ulong, Specified Ticket ... + */ + void RemoveSignal(ulong ticket) + { + // + bool has = NotEmptyZero(ticket) && + HasChild(signals); + if (!has) + { + return; + } + + // + int idx = -1; + has = FindSignal( + idx, + ticket // + ); + if (!has) + { + return; + } + + // + ArrayRemove( + signals, + idx, + 1 // + ); + } + + /** + * Check Can Apply Specified Target on Specified Position or not ... + * + * @param target: XTarget, reference to Specified Target for Apply ... + * @param position: XPosition, reference to Specified Position ... + * + * @return ( bool ) + */ + bool CanApplyTarget( + XTarget &target, + XPosition &position // + ) + { + // + bool result = false; + + // + // Validate ... + result = + target.IsValid() && + position.IsValid(); + if (!result) + { + return result; + } + + // + // Check Price Reached Targets Value and Distance ... + double targetDistance = (target.actingDistance > 0 ? target.actingDistance : 0) * position.GetPointsValue(); + result = + IsLong(position.type) + ? position.price >= target.target + targetDistance + : position.price <= target.target - targetDistance; + + // + return result; + } + + /** + * Apply Specified Target on Specified Position ... + * + * @param target: XTarget, reference to Specified Target for Apply ... + * @param position: XPosition, reference to Specified Position ... + * + * @return ( bool ) + */ + bool HandleApplyTarget( + XTarget &target, + XPosition &position // + ) + { + // + bool result = false; + + // + // Validate ... + result = + target.IsValid() && + position.IsValid() && + CanApplyTarget( + target, + position // + ); + if (!result) + { + return result; + } + + // + // Apply Target ... + string comment = NULL; + string message = NULL; + + // + // Do Risk Free if Provided ... + if (result && + target.doRF) + { + // + comment = "Taregt Manager do RF ..."; + result = trader.Modify( + position.ticket, + target.target, // SL ... + position.tp, // TP ... + comment // + ); + + // + // Handle Alert ... + if (result) + { + // + message = "Target Manager do RF " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") on: " + ToXString(position.price); + alert.SendAlert(message); + } + } + + // + // Do Risk Free on Entry if Provided ... + if (result && + target.doRFOnEntry) + { + // + comment = "Target Manager do RF on Entry ..."; + double actingDistance = position.GetPointsValue() * target.actingDistance; + bool isLong = IsLong(position.type); + double sl = position.entry + (isLong + ? actingDistance + : (-1 * actingDistance) // + ); + result = trader.Modify( + position.ticket, + sl, // SL ... + position.tp, // TP ... + comment // + ); + + // + // Handle Alert ... + if (result) + { + // + message = "Target Manager do RF " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") on Entry ..."; + alert.SendAlert(message); + } + } + + // + // Do Partial Close if Provided ... + if (result && + target.volumeMultiplier > 0) + { + // + double volume = NormalizeVolume((position.volume * target.volumeMultiplier), position.symbol); + if (volume != position.volume) + { + // + comment = "Target Manager do Partial Close ..."; + result = trader.ClosePartial( + position.ticket, + volume, + comment // + ); + + // + // Handle Alert ... + if (result) + { + // + message = "Target Manager do Partial Close " + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") by: " + ToXString(volume); + alert.SendAlert(message); + } + } + } + + // + // Handle Replace TP ... + if (result && + target.tpValue > 0) + { + // + // Validate TP Value ... + bool isLong = IsLong(position.type); + bool isValid = isLong + ? target.tpValue > position.price && + target.tpValue > position.tp + : target.tpValue < position.price && + target.tpValue < position.tp; + if (isValid) + { + // + comment = "Target Manager Change TP ..."; + result = trader.Modify( + position.ticket, + position.sl, // SL ... + target.tpValue, // TP ... + comment // + ); + + // + // Handle Alert ... + if (result) + { + // + message = "Target Manager Change TP of" + ToXString(position.type) + " Position (" + ToXString(position.ticket) + ") to: " + ToXString(target.tpValue) + " ..."; + alert.SendAlert(message); + } + } + } + + // + return result; + } + + // + // Private ... + private: + // + + // + // Required Event Handlers ... + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + TOnForceClose mOnForceCloseEventHandlers[]; +}; + +// + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-trade-manager.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XCXTradeManager +// Description: provides all Trade Management requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Classes/x-saherelm.x-data.collector.class.mq5" +#include "../Classes/x-saherelm.x-guard.class.mq5" +#include "../Classes/x-saherelm.x-target.class.mq5" +#include "../Classes/x-saherelm.x-poi.drawer.class.mq5" +#include "../Classes/x-saherelm.x-trade.class.mq5" +#include "../Classes/x-saherelm.x-volume.class.mq5" + +// +// Implementation ... +class XCTradeManager : public XCBase +{ + // + // Public ... + public: + // + // Props ... + XCAlert *alert; + XCGuard *guard; + XCTrade *trader; + XCTarget *target; + XCVolume *volume; + XTimeTracker timeTracker; + XCDataCollector *collector; + + // + XCPOIDrawer *drawer; + + // + TCheckForGuard checkForGuardEventListener; + + // + // Constructor ... + XCTradeManager( + XCAlert *_alert, + XCTrade *_trader, + XCVolume *_volume, + XCGuard *_guard, + XCTarget *_target // + ) + { + // + alert = _alert; + guard = _guard; + volume = _volume; + trader = _trader; + target = _target; + + // + drawer = new XCPOIDrawer(); + + // + allowTrade = true; + allowLongs = true; + allowShorts = true; + + // + reportTrades = true; + reportSignals = true; + reportProtector = true; + reportAfterTradesBalance = true; + + // + SaveTrades(false); + + // + collector = new XCDataCollector(); + + // + // Setting Collector Path ... + string mPath = (IsValid(alert.GetPrefix()) + ? alert.GetPrefix() + "\\" + : "") + + trader.mAccount.GetCompany(); + collector.Path(mPath); + } + + // + // Deconstructor ... + ~XCTradeManager() + { + // + Clean(trades); + + // + timeTracker.Clean(); + + // + delete drawer; + ZeroMemory(drawer); + + // + delete collector; + ZeroMemory(collector); + } + + // + // Properties ... + + // + bool SaveTrades() + { + return mSaveTrades; + } + + // + void SaveTrades(bool value) + { + mSaveTrades = value; + } + + // + bool SaveSignals() + { + return mSaveSignals; + } + + // + void SaveSignals(bool value) + { + mSaveSignals = value; + } + + // + bool SaveWins() + { + return mSaveWins; + } + + // + void SaveWins(bool value) + { + mSaveWins = value; + } + + // + bool SaveLosts() + { + return mSaveLosts; + } + + // + void SaveLosts(bool value) + { + mSaveLosts = value; + } + + // + bool SaveRestrictions() + { + return mSaveRestrictions; + } + + // + void SaveRestrictions(bool value) + { + mSaveRestrictions = value; + } + + // + // Setter(s) ... + + // + void SetSymbolConfigurations(string symbolConfiguration) + { + // + int count = 0; + bool has = false; + + // + // If Not Provided ... + has = IsSpecifiedValid(symbolConfiguration); + if (!has) + { + // + AddDefaultSymbolConfiguration(); + return; + } + + // + // Try to Parse Data ... + string symbolData[]; + count = SplitContent( + symbolData, + symbolConfiguration, + "]" // + ); + has = IsValidSize(count); + if (!has) + { + // + AddDefaultSymbolConfiguration(); + + // + SpecifiedClean(symbolData); + return; + } + + // + // Loop through Exists Symbol Data's ... + for (int i = 0; i < count; i++) + { + // + string iData = symbolData[i]; + + // + // Extract Data Parts ... + string iParts[]; + int iPartsCount = SplitContent( + iParts, + iData, + "|" // + ); + has = IsValidSize(iPartsCount); + if (has) + { + // + // Determines Required Parts ... + bool hasName = iPartsCount >= 1; + bool hasSymbol = iPartsCount >= 2; + bool hasPeriod = iPartsCount >= 3; + bool hasSessionsDescriptor = iPartsCount >= 4; + bool hasMaxAllowedSpred = iPartsCount >= 5; + bool hasMaxAllowedPositios = iPartsCount >= 6; + bool hasRestrictionDescriptor = iPartsCount >= 7; + + // + // Parts IDX ... + int partsIDX = 0; + + // + // Extract Name ... + string iName = + hasName + ? iParts[partsIDX] + : ""; + iName = EscapeString(iName); + partsIDX++; + + // + // Extract Symbol ... + string iSymbol = + hasSymbol + ? iParts[partsIDX] + : _Symbol; + iSymbol = EscapeString(iSymbol); + iSymbol = NormalizeSymbol(iSymbol); + partsIDX++; + + // + // Extract Period ... + ENUM_TIMEFRAMES iPeriod = + hasPeriod + ? ToPeriod(EscapeString(iParts[partsIDX])) + : _Period; + iPeriod = NormalizePeriod(iPeriod); + partsIDX++; + + // + // Extract Sessions Descriptor ... + string iSessionsDescriptor = + hasSessionsDescriptor + ? iParts[partsIDX] + : ""; + iSessionsDescriptor = EscapeString(iSessionsDescriptor); + partsIDX++; + + // + // Extract Max Allowed Sspread ... + double iMaxAllowedSpread = + hasMaxAllowedSpred + ? (double)(EscapeString(iParts[partsIDX])) + : 25; + partsIDX++; + + // + // Extract Max Allowedd Positions ... + int iMaxAllowedPositions = + hasMaxAllowedPositios + ? (int)(EscapeString(iParts[partsIDX])) + : 5; + partsIDX++; + + // + // Extract Restrictions Descriptor ... + string iRestrictionsDescriptor = + hasRestrictionDescriptor + ? iParts[partsIDX] + : ""; + iRestrictionsDescriptor = EscapeString(iRestrictionsDescriptor); + partsIDX++; + + // + XSymbolTradeConfig iConfig; + + // + // Initialize Config ... + has = iConfig.Init( + iName, + iSymbol, + iPeriod, + iSessionsDescriptor, + iMaxAllowedSpread, + iMaxAllowedPositions, + iRestrictionsDescriptor // + ); + if (has) + { + AddOrUpdateSymbolConfiguration(iConfig); + } + + // + // Cleanup Resources ... + iConfig.Clean(); + } + + // + // Cleanup Resources ... + SpecifiedClean(iParts); + } + + // + // Cleanup Resources ... + SpecifiedClean(symbolData); + } + + // + int FillSymbolConfigurations(XSymbolTradeConfig &dest[]) + { + // + SpecifiedClean(dest); + + // + Copy( + symbolTradeConfigs, + dest // + ); + + // + int result = ArraySize(dest); + + // + return result; + } + + // + void SetTradeReports( + bool _reportTrades, + bool _reportSignals, + bool _reportProtector, + bool _reportRestrictions, + bool _reportAfterTradesBalance // + ) + { + // + reportTrades = _reportTrades; + reportSignals = _reportSignals; + reportProtector = _reportProtector; + reportRestrictions = _reportRestrictions; + reportAfterTradesBalance = _reportAfterTradesBalance; + } + + // + void SetTradePermissions( + bool _allowTrade, + bool _allowLongs, + bool _allowShorts // + ) + { + // + allowTrade = _allowTrade; + allowLongs = _allowLongs; + allowShorts = _allowShorts; + } + + // + // Tools and Helpers ... + + /** + * Do All Position Managing Senaros ... + */ + void Manage() + { + // + // Handle Restrictions ... + HandleRestrictions(); + + // + // Managing Targets ... + target.Manage(); + + // + // Check Contains Trades for Managing ... + bool has = HasChild(trades); + if (!has) + { + return; + } + + // + // Update Required Infos of Trades ... + int count = ArraySize(trades); + for (int i = 0; i < count; i++) + { + // + has = trades[i].IsExecuted() && + !trades[i].IsFinalized(); + if (!has) + { + continue; + } + + // + XPosition iPosition; + has = trader.GetPosition( + trades[i].positionID, + iPosition // + ); + if (!has) + { + continue; + } + + // + // Update Trade Data ... + trades[i].swap = iPosition.swap; + trades[i].profit = iPosition.profit; + } + + // + // Do Trade Protection ... + Protect(); + } + + /** + * Do All Position Protection Here ... + */ + void Protect() + { + // + string prefix = "Protector: "; + int targetDistance = 5; + + // + bool has = HasChild(trades); + if (!has) + { + return; + } + + // + XPosition ownPosition[]; + XPosition ownLongPosition[]; + XPosition ownShortPosition[]; + + // + int count = ArraySize(trades); + for (int i = 0; i < count; i++) + { + // + has = + trades[i].IsExecuted() && + !trades[i].IsFinalized(); + if (!has) + { + continue; + } + + // + XPosition iPosition; + has = trader.GetPosition( + trades[i].positionID, + iPosition // + ); + if (!has) + { + continue; + } + + // + AddRef( + iPosition, + ownPosition // + ); + + // + if (IsLong(iPosition.type)) + { + // + AddRef( + iPosition, + ownLongPosition // + ); + } + else + { + // + AddRef( + iPosition, + ownShortPosition // + ); + } + } + + // + has = HasChild(ownPosition); + if (!has) + { + // + Clean(ownPosition); + Clean(ownLongPosition); + Clean(ownShortPosition); + + // + return; + } + + // + XGuard guards[]; + int guardsCount = CheckForGuard(guards); + bool hasGuard = IsValidSize(guardsCount); + if (hasGuard) + { + // + guard.DoGuards(guards); + } + + // + double swapSum = 0; + double profitSum = 0; + double commissionSum = 0; + + // + // Calculate Required Data On Collection ... + count = ArraySize(ownPosition); + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = ownPosition[i]; + + // + swapSum += iPosition.swap; + profitSum += iPosition.profit; + commissionSum += iPosition.commission; + } + + // + // Do Collection Protectiong ... + + // + // Handle Force Close At Time ... + has = HandleForceCloseAtTime(); + if (has) + { + // + Clean(ownPosition); + Clean(ownLongPosition); + Clean(ownShortPosition); + + // + return; + } + + // + // Do Signle Protections ... + for (int i = 0; i < count; i++) + { + // + // Select Position ... + XPosition iPosition = ownPosition[i]; + int idx = -1; + has = HasTrade( + idx, + iPosition.ticket // + ); + if (!has) + { + continue; + } + + // + bool isLong = IsLong(iPosition.type); + double points = GetPoints(iPosition.symbol); + + // + // Handle RF On Targets ... + if (iPosition.profit > 0) + { + // + // Handle Risk Free On Targets ... + XTarget targets[]; + Copy( + trades[idx].signal.targets, + targets // + ); + int targetsCount = ArraySize(targets); + has = IsValidSize(targetsCount); + if (has) + { + // + for (int j = 0; j < targetsCount; j++) + { + // + XTarget jTarget = targets[j]; + + // + int appliedTargetIDX = -1; + + // + // Check Target is Applied Before or Not ... + has = + !trades[idx].signal.isTargetApplied + ? true + : trades[idx].signal.appliedTargetIDX < j; + if (!has) + { + continue; + } + + // + // Check Traget Validation ... + has = + iPosition.sl == 0 + ? true + : isLong + ? iPosition.sl < jTarget.target + : iPosition.sl > jTarget.target; + if (!has) + { + continue; + } + + // + double targetDelta = isLong + ? jTarget.target + (targetDistance * points) + : jTarget.target - (targetDistance * points); + + // + // Can Risk Free ... + bool canRF = + jTarget.doRF && + jTarget.target > 0 && + (isLong + ? jTarget.target > iPosition.entry + : jTarget.target < iPosition.entry) && + (isLong + ? iPosition.price > targetDelta + : iPosition.price < targetDelta); + + // + // Can Partial Close ... + bool canPC = + jTarget.volumeMultiplier > 0 && + jTarget.target > 0 && + (isLong + ? jTarget.target > iPosition.entry + : jTarget.target < iPosition.entry) && + (isLong + ? iPosition.price > targetDelta + : iPosition.price < targetDelta); + bool canRFPC = canRF || + canPC; + if (canRFPC) + { + // + // Handle Risk Free ... + bool isRFDone = false; + if (canRF) + { + // + double tp = iPosition.tp; + double sl = jTarget.target; + string comment = "RF On Target ..."; + isRFDone = trader.Modify( + iPosition.ticket, + sl, + tp, + comment // + ); + } + + // + // Handle Partail Close ... + bool isPCDone = false; + if (canPC) + { + // + double _volume = jTarget.volumeMultiplier * iPosition.volume; + _volume = NormalizeVolume(_volume, iPosition.symbol); + string comment = "RF On Target ..."; + isPCDone = trader.ClosePartial( + iPosition.ticket, + _volume, + comment // + ); + } + + // + // Handle Report Action ... + bool isRFPCDone = isRFDone || + isPCDone; + if (isRFPCDone) + { + // + trades[idx].signal.appliedTargetIDX = j; + trades[idx].signal.isTargetApplied = true; + + // + string message = prefix + + ToXString(iPosition.type) + + " Position: " + + ToXString(iPosition.ticket) + + (isRFDone ? " RF" : "") + + (isPCDone ? " PC" : "") + + " On Traget: " + ToXString(jTarget.target) + + " Successfully ..."; + HandleReportProtector(message); + } + } + } + } + } + } + } + + /** + * Check Can Analyse Market based on Configurations ... + * + * @param symbol: Symbol + * @param period: Period + * @param time: Analysing Time + * + * @return ( bool ) + */ + bool CanAnalyse( + string symbol, + ENUM_TIMEFRAMES period, + datetime time // + ) + { + // + bool result = false; + + // + // Finding Symbol Configuration Index ... + int idx = FindSymbolConfigurationIndex( + symbol, + period // + ); + + // + // If Not Exists ... + if (!IsValidIndex(idx)) + { + // + result = true; + return result; + } + + // + // If Exists ... + + // + // Check Session is Active ... + result = symbolTradeConfigs[idx].CanTrade(time); + if (!result) + { + return result; + } + + // + // Check Symbol Restrictions ... + result = symbolTradeConfigs[idx].IsRestricted(time); + if (!result) + { + return result; + } + + // + return result; + } + + /** + * Check Signal Execution Conditions ... + * + * @param signal: XSignal instance reference ... + * @param executionResult: ENUM_X_SIGNAL_EXECUTION_RESULT member reference ... + * + * @return ( bool ) + */ + bool CheckSignal( + XSignal &signal, + ENUM_X_SIGNAL_EXECUTION_RESULT &executionResult // + ) + { + // + bool result = false; + + // + // Cleanup ... + executionResult = X_SIGNAL_EXECUTION_UNKNOWN; + + // + // Validate Signal ... + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + // Reporting Signal ... + if (reportSignals) + { + // + string message = signal.GetMessage("Provided"); + alert.SendAlert(message); + } + + // + SaveSignal(signal); + + // + // Check Trade Permission ... + result = AllowTrade(signal.type); + if (!result) + { + // + result = false; + executionResult = X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED; + + // + return result; + } + + // + // Check Sessions and Restrictions ... + result = CanAnalyse( + signal.symbol, + signal.period, + signal.time // + ); + if (!result) + { + // + executionResult = X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED; + + // + return result; + } + + // + // Check Signal Spread ... + int idx = FindSymbolConfigurationIndex( + signal.symbol, + signal.period // + ); + if (IsValidIndex(idx)) + { + // + double spread = GetSpread(signal.symbol); + result = + symbolTradeConfigs[idx].maxAllowedSpread > 0 + ? spread <= symbolTradeConfigs[idx].maxAllowedSpread + : true; + if (!result) + { + // + executionResult = X_SIGNAL_EXECUTION_FAILED_SPREAD; + + // + return result; + } + + // + // Checking Max Allowed Positions ... + if (symbolTradeConfigs[idx].maxAllowedPositions > 0) + { + // + XPosition positions[]; + ENUM_X_POSITION_TYPES mType = IsLong(signal.type) + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; + int positionsCount = trader.GetPositions( + positions, + symbolTradeConfigs[idx].symbol, + NULL, // All Providers ... + symbolTradeConfigs[idx].period, + mType, + true, // Filter By Magic ... + true // Force Clean ... + ); + result = !IsValidSize(positionsCount) || + (IsValidSize(positionsCount) && + positionsCount < symbolTradeConfigs[idx].maxAllowedPositions); + + // + // Cleanup Resources ... + SpecifiedClean(positions); + } + } + + // + return result; + } + + /** + * Check Allow Trade or not .. + * + * @param type: ENUM_POSITIO_TYPE + * + * @return ( bool ) + */ + bool AllowTrade(ENUM_POSITION_TYPE type) + { + // + bool result = false; + + // + result = allowTrade; + if (!result) + { + return result; + } + + // + result = + (IsLong(type) && allowLongs) || + (IsShort(type) && allowShorts); + + // + return result; + } + + /** + * Execute Specified Signal ... + * + * @param signal: XSignal instance reference ... + * @param conditions: XCATBEAStrategyConditions instance reference ... + * + * @return ( bool ) + */ + bool Execute(XSignal &signal) + { + // + bool result = false; + + // + result = signal.IsValid(); + if (!result) + { + return result; + } + + // + int idx = -1; + bool isExists = HasTrade( + idx, + signal // + ); + result = !isExists; + if (!result) + { + return result; + } + + // + ENUM_X_SIGNAL_EXECUTION_RESULT executionResult; + + // + // Checking Signal For Execution ... + result = CheckSignal( + signal, + executionResult // + ); + if (result) + { + // + result = trader.ExecuteSignal( + signal, + executionResult // + ); + } + + // + // Alert Signal Execution ... + if (reportTrades) + { + // + string executionMessage = ToString(executionResult); + + // + string message = NULL; + if (result) + { + message = signal.GetMessage("Executed"); + } + else + { + message = signal.GetMessage("Failed due (" + executionMessage + ")"); + } + + // + alert.SendAlert(message); + } + + // + if (result) + { + // + // Create Trade Struct ... + XTradeInfo iTrade; + + // + ulong positionID = trader.GetLastOpenPositionTicket(); + double commission = trader.GetPositionCommission(positionID); + + // + iTrade.signal = signal; + iTrade.positionID = positionID; + iTrade.commission = commission; + iTrade.signaledAt = signal.time; + iTrade.executedAt = TimeCurrent(); + iTrade.conditions = signal.conditions; + + // + AddRef( + iTrade, + trades // + ); + } + + // + return result; + } + + /** + * Retrieve Specified Positions ... + * + * @param positions: XPosition instance Reference Array, which holds Founded Positions ... + * @param symbol: string, Specified Symbol Name ... + * @param provider: string, Specified Provider Name ... + * @param period: ENUM_TIMEFRAMES, Specified Period ... + * + * @return ( int ) + */ + int GetPositions( + XPosition &positions[], + string symbol, + string provider, + ENUM_TIMEFRAMES period // + ) + { + // + int result = 0; + + // + Clean(positions); + + // + bool has = + IsValid(symbol) && + IsValid(period) && + IsValid(provider); + if (!has) + { + return result; + } + + // + result = trader.GetPositions( + positions, + symbol, + provider, + period, + NULL, // All Types ... + true, // Filter By Magic ... + true // Force Clean ... + ); + + // + result = ArraySize(positions); + + // + return result; + } + + /** + * Handle Signal Recieved ... + * + * @param signal: XSignal + */ + void HandleSignal(XSignal &signal) + { + // + // Validate Signal ... + if (!signal.IsValid()) + { + return; + } + + // + // Check Signal ... + bool isExecuted = false; + ENUM_X_SIGNAL_EXECUTION_RESULT signalExecutionResult; + bool canExecute = CheckSignal( + signal, + signalExecutionResult // + ); + if (canExecute) + { + // + HandleSignalVolume(signal); + isExecuted = Execute(signal); + } + + // + // Draw Signal Object ... + XCSignalObject *signalObj; + bool has = drawer.DrawSignal( + signal, + signalObj, + 4 // + ); + if (has) + { + mObjects.Add(signalObj); + } + } + + /** + * Handle Position Take Profit ... + * + * @param deal: XDeal instance reference ... + */ + void HandleTP(const XDeal &deal) + { + // + // Check Ticket Exists or not ... + int idx = -1; + bool isExists = HasTrade( + idx, + deal.positionId // + ); + if (!isExists) + { + return; + } + + // + // Apply Required Data ... + trades[idx].swap = deal.swap; + trades[idx].profit = deal.profit; + trades[idx].finalizedAt = TimeCurrent(); + trades[idx].finalize = XTRADE_FINAL_TP; + + // + // Save Trade ... + SaveWin(trades[idx]); + SaveTrade(trades[idx]); + + // + // Handle Balance Reporting ... + string prefix = "TP: " + ToXString(trades[idx].profit); + HandleReportBalance(prefix); + + // + // Handle Symbol Config ... + + // + int configIdx = FindSymbolConfigurationIndex( + trades[idx].signal.symbol, + trades[idx].signal.period // + ); + isExists = IsValidIndex(configIdx); + if (isExists) + { + // + symbolTradeConfigs[configIdx].profits += 1; + symbolTradeConfigs[configIdx].managedTPs += 1; + symbolTradeConfigs[configIdx].managedProfits += trades[idx].profit; + } + + // + RemoveTrade(idx); + + // + target.HandleOnTakeProfitTriggered(deal); + } + + /** + * Handle Position Stop Loss ... + * + * @param deal: XDeal instance reference ... + */ + void HandleSL(const XDeal &deal) + { + // + // Check Ticket Exists or not ... + int idx = -1; + bool isExists = HasTrade( + idx, + deal.positionId // + ); + if (!isExists) + { + return; + } + + // + // Apply Required Data ... + trades[idx].swap = deal.swap; + trades[idx].profit = deal.profit; + trades[idx].finalizedAt = TimeCurrent(); + trades[idx].finalize = XTRADE_FINAL_SL; + + // + // Save Trade ... + SaveTrade(trades[idx]); + + // + // Handle Balance Reporting ... + string prefix = "SL: " + ToXString(trades[idx].profit); + HandleReportBalance(prefix); + + // + // Handle Symbol Info ... + + // + bool isInProfit = trades[idx].profit > 0; + if (isInProfit) + { + SaveWin(trades[idx]); + } + else + { + SaveLost(trades[idx]); + } + + // + // Handle Symbol Config ... + + // + int configIdx = FindSymbolConfigurationIndex( + trades[idx].signal.symbol, + trades[idx].signal.period // + ); + isExists = IsValidIndex(configIdx); + if (isExists) + { + // + if (isInProfit) + { + // + symbolTradeConfigs[configIdx].profits += 1; + symbolTradeConfigs[configIdx].managedTPs += 1; + } + else + { + // + symbolTradeConfigs[configIdx].losses += 1; + symbolTradeConfigs[configIdx].managedSLs += 1; + } + + // + symbolTradeConfigs[configIdx].managedProfits += trades[idx].profit; + } + + // + RemoveTrade(idx); + + // + target.HandleOnStopLossTriggered(deal); + } + + /** + * Handle Position Force Close ... + * + * @param deal: XDeal instance reference ... + */ + void HandleForceClose(const XPosition &position) + { + // + // Check Ticket Exists or not ... + int idx = -1; + bool isExists = HasTrade( + idx, + position.ticket // + ); + if (!isExists) + { + return; + } + + // + bool isInProfit = position.profit > 0; + + // + // Apply Required Data ... + trades[idx].swap = position.swap; + trades[idx].profit = position.profit; + trades[idx].finalizedAt = TimeCurrent(); + trades[idx].commission = position.commission; + trades[idx].finalize = isInProfit + ? XTRADE_FINAL_CLOSE_IN_PROFIT + : XTRADE_FINAL_CLOSE_IN_LOSE; + + // + // Save Trade ... + SaveTrade(trades[idx]); + if (isInProfit) + { + SaveWin(trades[idx]); + } + else + { + SaveLost(trades[idx]); + } + + // + // Handle Balance Reporting ... + string prefix = "Force Close " + + (isInProfit + ? "Profit" + : "Loss") + + ": " + + ToXString(trades[idx].profit); + HandleReportBalance(prefix); + + // + // Handle Symbol Config ... + + // + int configIdx = FindSymbolConfigurationIndex( + trades[idx].signal.symbol, + trades[idx].signal.period // + ); + isExists = IsValidIndex(configIdx); + if (isExists) + { + // + if (isInProfit) + { + // + symbolTradeConfigs[configIdx].profits += 1; + symbolTradeConfigs[configIdx].managedTPs += 1; + } + else + { + // + symbolTradeConfigs[configIdx].losses += 1; + symbolTradeConfigs[configIdx].managedSLs += 1; + } + + // + symbolTradeConfigs[configIdx].managedProfits += trades[idx].profit; + } + + // + RemoveTrade(idx); + + // + target.HandleOnPositionForceClosed( + position.ticket, + position, + position.comment // + ); + } + + /** + * Handle All Symbols Config Force Close At Time ... + * + * @return ( bool ) + */ + bool HandleForceCloseAtTime() + { + // + bool result = false; + + // + // Check Symbol Config Exists ... + result = HasChild(symbolTradeConfigs); + if (!result) + { + return result; + } + + // + result = false; + int count = ArraySize(symbolTradeConfigs); + for (int i = 0; i < count; i++) + { + // + // Check Can Force Closed At ... + bool has = IsSpecifiedValid(symbolTradeConfigs[i].closeAllOpenTradesAt); + if (!has) + { + continue; + } + + // + // Parse Date ... + datetime forceCloseTime = ParseDateTimeFromTimeString(symbolTradeConfigs[i].closeAllOpenTradesAt); + has = IsTimeInRange( + TimeCurrent(), + forceCloseTime // + ) && + !symbolTradeConfigs[i].isForceCloseAtTime; + if (!has) + { + continue; + } + + // + // Selecting Positions ... + XTradeInfo iTrades[]; + int iTradesCount = FillSymbolConfigurationTrades( + symbolTradeConfigs[i], + iTrades // + ); + has = IsValidSize(iTradesCount); + if (!has) + { + // + SpecifiedClean(iTrades); + continue; + } + + // + // Converts Trades to Positions ... + XPosition iPositions[]; + int iPositionsCount = ToXPositions( + iTrades, + iPositions // + ); + has = IsValidSize(iPositionsCount); + if (!has) + { + // + SpecifiedClean(iTrades); + SpecifiedClean(iPositions); + continue; + } + + // + // Do Force Closing ... + has = HandleForceCloseTrades(iPositions); + if (has && !result) + { + result = true; + } + + // + // Cleanup Resources ... + SpecifiedClean(iTrades); + SpecifiedClean(iPositions); + } + + // + return result; + } + + /** + * Handle Position Partially Closed Event ... + * + * @param ticket: ULONG ... + * @param profit: double ... + * @param comment: string ... + */ + void HandlePartiallyClosed( + const ulong ticket, + const double profit, + const string comment // + ) + { + // + // Handle Balance Reporting ... + string prefix = "Partially Closed: " + ToXString(ticket); + + // + // Handle Balance Reporting ... + HandleReportBalance(prefix); + } + + /** + * Handle Guard Events ... + * + * @param action: ENUM_X_GUARD_ACTIONS + * @param positions: XPosition[] + */ + void HandleGuardEvent( + ENUM_X_GUARD_ACTIONS action, + XPosition &positions[] // + ) + { + } + + /** + * Handle Signal Executed Event ... + * + * @param signal: XSignal, reference to Executed Signal ... + */ + void HandleSignalExecuted(XSignal &signal) + { + target.AddExecutedSignal(signal); + } + + // + // Protected ... + protected: + // + // Tools ... + + // + string GetTradeFilePath(XTradeInfo &trade) + { + // + string fileName = trade.GetFileName(); + + // + return GetTradeFilePath(fileName); + } + + // + string GetTradeFilePath(string fileName) + { + // + string result = NULL; + + // + result = collector + .GetFilePath("Trades" + "\\" + fileName); + + // + return result; + } + + // + string GetSignalFilePath(string fileName) + { + // + string result = NULL; + + // + result = collector + .GetFilePath("Signals" + "\\" + fileName); + + // + return result; + } + + // + string GetWinsFilePath(XTradeInfo &trade) + { + // + string result = NULL; + + // + result = collector + .GetFilePath("Conditions" + "\\" + + trade.signal.symbol + "\\" + + ToXString(trade.signal.period) + "_wins"); + + // + return result; + } + + // + string GetLostsFilePath(XTradeInfo &trade) + { + // + string result = NULL; + + // + result = collector + .GetFilePath("Conditions" + "\\" + + trade.signal.symbol + "\\" + + ToXString(trade.signal.period) + "_losts"); + + // + return result; + } + + // + string GetRestrictionsFilePath(string symbol) + { + // + string result = NULL; + + // + if (!IsValid(symbol)) + { + return result; + } + + // + result = collector + .GetFilePath("Restrictions" + "\\" + symbol); + + // + return result; + } + + // + void HandleReportBalance(string prefix = NULL) + { + // + if (!reportAfterTradesBalance) + { + return; + } + + // + double balance = trader.mAccount.GetBalance(); + string currency = trader.mAccount.GetCurrency(); + + // + string message = + (IsValid(prefix) + ? prefix + " | " + : "") + + "Account Balance: " + ToXString(balance) + currency; + alert.SendAlert(message); + } + + // + void HandleReportProtector(string message = NULL) + { + // + if (!reportProtector) + { + return; + } + + // + alert.SendAlert(message); + } + + /** + * Handle All Exists Symbol Configurations Restrictions ... + */ + void HandleRestrictions() + { + // + // Count Symbol Configurations ... + int count = ArraySize(symbolTradeConfigs); + bool has = IsValidSize(count); + if (!has) + { + return; + } + + // + // Handle Restrictions ... + datetime cTime = TimeCurrent(); + bool isNewDay = timeTracker.IsNewDay(); + for (int i = 0; i < count; i++) + { + // + // Reset Force Close At Time ... + if (isNewDay) + { + symbolTradeConfigs[i].isForceCloseAtTime = false; + } + + // + // Handle Restrictions ... + symbolTradeConfigs[i].HandleRestrictions(cTime); + } + } + + /** + * Apply Signal Volume ... + * + * @param signal: XSignal + */ + void HandleSignalVolume(XSignal &signal) + { + // + // Validate ... + if (!signal.IsValid()) + { + return; + } + + // + // Handle Volume Management ... + double iVolume = volume.CalculateVolume(signal); + bool has = iVolume > X_MIN_VOLUME && + iVolume != signal.volume; + if (has) + { + signal.volume = iVolume; + } + + // + // Here we Can Implement Custom Signalling Volume Management + // based on Different Symbol Configurations ... + } + + /** + * Handle Force Close Trades ... + */ + bool HandleForceCloseTrades( + XPosition &positions[] // + ) + { + // + bool result = false; + + // + result = HasChild(positions); + if (!result) + { + return result; + } + + // + string prefix = "Protector: "; + string comment = "Force Close ..."; + + // + int count = ArraySize(positions); + for (int i = 0; i < count; i++) + { + HandleForceClose(positions[i]); + } + + // + result = IsValidSize(count); + if (result) + { + // + string message = prefix + "Force Close (" + ToXString(count) + ") Trades at Specified Time ..."; + HandleReportProtector(message); + } + + // + return result; + } + + /** + * Check For Guards ... + * + * @param dest: XGuard[] + */ + int CheckForGuard(XGuard &dest[]) + { + // + int result = 0; + + // + // Cleanup Dest ... + SpecifiedClean(dest); + + // + // Check For Guards ... + if (checkForGuardEventListener != NULL) + { + // + XPosition positions[]; + trader.GetPositions(positions); + result = checkForGuardEventListener(dest, positions, 0); + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Save Trades ... + bool SaveTrade( + XTradeInfo &trade, + bool includeSummary = true, + bool includeSignal = true, + bool includeConditions = true // + ) + { + // + bool result = false; + + // + if (!mSaveTrades) + { + return result; + } + + // + string filePath = GetTradeFilePath(trade); + result = IsValid(filePath); + if (!result) + { + return result; + } + + // + string content = trade.ToString( + includeSummary, + includeSignal, + includeConditions // + ); + + // + result = collector.Save( + filePath, + content // + ); + + // + return result; + } + + // + // Save Signals ... + bool SaveSignal(XSignal &signal) + { + // + bool result = false; + + // + // Check Signal Save is Enabled ... + if (!mSaveSignals) + { + return result; + } + + // + // Check Signal Validation ... + if (!signal.IsValid()) + { + return result; + } + + // + // Retrieve Signal File Name ... + string signalFileName = signal.GetFileName(); + result = IsValid(signalFileName); + if (!result) + { + return result; + } + + // + // Retriev and Validate File Name ... + string filePath = GetSignalFilePath(signalFileName); + result = IsValid(filePath); + if (!result) + { + return result; + } + + // + // Generate Content ... + string content = ""; + content += + ToXString("----------------") + "\n" + + ToXString("Signal: ") + "\n" + + ToXString("----------------") + "\n" + + signal.ToString() + "\n"; + content += + ToXString("----------------") + "\n" + + ToXString("Conditions: ") + "\n" + + ToXString("----------------") + "\n" + + signal.conditions + "\n"; + + // + // Save Content to File ... + result = collector.Save( + filePath, + content // + ); + + // + // Return Result ... + return result; + } + + // + bool SaveWin(XTradeInfo &trade) + { + // + bool result = false; + + // + if (!mSaveWins) + { + return result; + } + + // + string filePath = GetWinsFilePath(trade); + result = IsValid(filePath); + if (!result) + { + return result; + } + + // + // Preparing Conditions Content ... + string content = trade.GetConditionsString(); + + // + result = collector.Append( + filePath, + content // + ); + + // + return result; + } + + // + bool SaveLost(XTradeInfo &trade) + { + // + bool result = false; + + // + if (!mSaveLosts) + { + return result; + } + + // + string filePath = GetLostsFilePath(trade); + result = IsValid(filePath); + if (!result) + { + return result; + } + + // + // Preparing Conditions Content ... + string content = trade.GetConditionsString(); + + // + result = collector.Append( + filePath, + content // + ); + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + CArrayObj mObjects; + + // + bool allowTrade; + bool allowLongs; + bool allowShorts; + + // + bool mSaveWins; + bool mSaveLosts; + bool mSaveTrades; + bool mSaveSignals; + bool mSaveRestrictions; + + // + bool reportTrades; + bool reportSignals; + bool reportProtector; + bool reportRestrictions; + bool reportAfterTradesBalance; + + // + XTradeInfo trades[]; + XSymbolTradeConfig symbolTradeConfigs[]; + + /** + * Find Executed Trade by Providing Position Ticket ... + * + * @param index: int reference, holding founded item index ... + * @param ticket: ulong, Specified Position Ticket ... + * + * @return ( bool ) + */ + bool HasTrade( + int &index, + ulong ticket // + ) + { + // + bool result = false; + + // + index = -1; + + // + result = + ticket > 0 && + HasChild(trades); + if (!result) + { + return result; + } + + // + int count = ArraySize(trades); + for (int i = 0; i < count; i++) + { + // + XTradeInfo iTrade = trades[i]; + + // + result = + iTrade.HasSignal() && + iTrade.IsExecuted() && + iTrade.positionID == ticket; + if (result) + { + // + index = i; + + // + iTrade.Clean(); + break; + } + + // + iTrade.Clean(); + } + + // + result = IsValidIndex(index); + + // + return result; + } + + /** + * Find Trade Item By Signal ... + * + * @param index: int reference, holding founded item index ... + * + * @return ( bool ) + */ + bool HasTrade( + int &index, + XSignal &signal // + ) + { + // + bool result = false; + + // + index = -1; + + // + result = + signal.IsValid() && + HasChild(trades); + if (!result) + { + return result; + } + + // + int count = ArraySize(trades); + for (int i = 0; i < count; i++) + { + // + XTradeInfo iTrade = trades[i]; + + // + result = + iTrade.HasSignal() && + iTrade.signal.IsSameAs(signal); + if (result) + { + // + index = i; + + // + iTrade.Clean(); + break; + } + + // + iTrade.Clean(); + } + + // + result = IsValidIndex(index); + + // + return result; + } + + /** + * Remove a Trade From List ... + * + * @param index: int ... + */ + void RemoveTrade(int index) + { + // + bool has = + HasChild(trades) && + IsValidIndex(index) && + index < ArraySize(trades); + if (!has) + { + return; + } + + // + ArrayRemove( + trades, + index, + 1 // + ); + } + + // + void AddOrUpdateSymbolConfiguration(XSymbolTradeConfig &config) + { + // + // Check Validation ... + bool has = config.IsValid(); + if (!has) + { + return; + } + + // + // Check Index ... + int idx = FindSymbolConfigurationIndex(config); + has = IsValidIndex(idx); + if (has) + { + // + // Update Exists ... + symbolTradeConfigs[idx] = config; + } + else + { + // + // Add New ... + AddRef( + config, + symbolTradeConfigs // + ); + } + } + + // + void AddDefaultSymbolConfiguration() + { + // + // Define new Configuration ... + XSymbolTradeConfig iConfig; + + // + // Check Initialization ... + bool has = iConfig.Init( + "Default", + _Symbol, + _Period // + ); + + // + // Add Or Update ... + if (has) + { + AddOrUpdateSymbolConfiguration(iConfig); + } + + // + // Clean Resources ... + iConfig.Clean(); + } + + // + int FindSymbolConfigurationIndex(XSymbolTradeConfig &config) + { + // + int result = -1; + + // + if (!config.IsValid() || !SpecifiedHasChild(symbolTradeConfigs)) + { + return result; + } + + // + int count = ArraySize(symbolTradeConfigs); + for (int i = 0; i < count; i++) + { + // + if (symbolTradeConfigs[i].IsSame(config)) + { + // + result = i; + break; + } + } + + // + return result; + } + + // + int FillSymbolConfigurationTrades( + XSymbolTradeConfig &config, + XTradeInfo &dest[] // + ) + { + // + int result = 0; + + // + SpecifiedClean(dest); + + // + // Check Trades ... + int count = ArraySize(trades); + if (!IsValidSize(count)) + { + return result; + } + + // + // Validate Config ... + if (!config.IsValid()) + { + return result; + } + + // + // Find Config ... + int idx = FindSymbolConfigurationIndex(config); + if (!IsValidIndex(idx)) + { + return result; + } + + // + bool has = false; + string symbol = symbolTradeConfigs[idx].symbol; + ENUM_TIMEFRAMES period = symbolTradeConfigs[idx].period; + for (int i = 0; i < count; i++) + { + // + has = + trades[i].signal.symbol == symbol && + trades[i].signal.period == period && + trades[i].positionID > 0; + if (!has) + { + continue; + } + + // + AddRef( + trades[i], + dest // + ); + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + int FindSymbolConfigurationIndex( + string symbol, + ENUM_TIMEFRAMES period // + ) + { + // + int result = -1; + + // + // Validate Args ... + if ( + !IsSpecifiedValid(symbol) || + !IsSpecifiedValid(period) || + !HasChild(symbolTradeConfigs)) + { + return result; + } + + // + int count = ArraySize(symbolTradeConfigs); + for (int i = 0; i < count; i++) + { + // + if (symbolTradeConfigs[i].symbol == symbol && + symbolTradeConfigs[i].period == period) + { + // + result = i; + break; + } + } + + // + return result; + } + + // + // Tools ... + + // + int ToXPositions( + XTradeInfo &source[], + XPosition &dest[] // + ) + { + // + int result = 0; + + // + SpecifiedClean(dest); + + // + int count = ArraySize(source); + bool has = IsValidSize(count); + if (!has) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + XPosition iPosition; + has = trader.GetPosition( + source[i].positionID, + iPosition); + if (has) + { + // + AddRef( + iPosition, + dest // + ); + } + + // + iPosition.Clean(); + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + string EscapeString(string value) + { + // + string result = value; + + // + if (!IsSpecifiedValid(value)) + { + return result; + } + + // + StringReplace( + result, + "[", + "" // + ); + + // + StringReplace( + result, + "]", + "" // + ); + + // + StringReplace( + result, + "|", + "" // + ); + + // + result = Trim(result); + + // + return result; + } +}; + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-trade.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// ---------------------------------------------- +// Name: XSCTrade +// Description: provides all Trade requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Classes/x-saherelm.x-account.class.mq5" +#include "../Classes/x-saherelm.x-alert.class.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// +// Definitions ... + +// +// Overrides ... + +// +// XCTrade Base Class ... +class XCTradeBase : public CTrade +{ + public: + // + // Modify Specific Position, by Specific Comment ... + bool PositionModify( + const string symbol, // Symbol + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!SelectPosition(symbol)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.symbol = symbol; + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + bool PositionModify( + const ulong ticket, // Position Ticket + const double sl, // Stop Loss + const double tp, // Take Profit + const string comment = "" // Comment For Modify + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // setting request + m_request.action = TRADE_ACTION_SLTP; + m_request.position = ticket; + m_request.symbol = PositionGetString(POSITION_SYMBOL); + m_request.magic = m_magic; + m_request.sl = sl; + m_request.tp = tp; + + // + // Specified Comment ... + if (StringLen(comment) > 0) + { + m_request.comment = comment; + } + + // + // action and return the result + return (OrderSend(m_request, m_result)); + } + + // + // Close Specific Position, by Specific Comment ... + bool PositionClose( + const string symbol, // Symbol + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + bool partial_close = false; + int retry_count = 10; + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + do + { + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specify Comment ... + m_request.comment = comment; + + // + // check volume + double max_volume = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); + if (m_request.volume > max_volume) + { + // + m_request.volume = max_volume; + partial_close = true; + } + else + { + partial_close = false; + } + + // + // hedging? just send order + if (IsHedging()) + { + return (OrderSend(m_request, m_result)); + } + + // + // order send + if (!OrderSend(m_request, m_result)) + { + // + if (--retry_count != 0) + { + continue; + } + + // + if (retcode == TRADE_RETCODE_DONE_PARTIAL) + { + m_result.retcode = retcode; + } + + // + return (false); + } + + // + //--- WARNING. If position volume exceeds the maximum volume allowed for deal, + //--- and when the asynchronous trade mode is on, for safety reasons, position is closed not completely, + //--- but partially. It is decreased by the maximum volume allowed for deal. + if (m_async_mode) + { + break; + } + + // + retcode = TRADE_RETCODE_DONE_PARTIAL; + if (partial_close) + { + Sleep(1000); + } + } while (partial_close); + + // + // succeed + return (true); + } + bool PositionClose( + const ulong ticket, // Position Ticket + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = PositionGetDouble(POSITION_VOLUME); + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specify Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } + + // + // Partial Close Specific Position, by Specific Comment ... + bool PositionClosePartial( + const string symbol, // Symbol + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + uint retcode = TRADE_RETCODE_REJECT; + + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if (SelectPosition(symbol)) + { + // + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + } + else + { + // + // position not found + m_result.retcode = retcode; + return (false); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + m_request.position = PositionGetInteger(POSITION_TICKET); + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // hedging? just send order + return (OrderSend(m_request, m_result)); + } + bool PositionClosePartial( + const ulong ticket, // Position Ticket + const double volume, // Partial Closing Volume + const ulong deviation, // Deviation + const string comment = "" // Comment For Close + ) + { + // + // check stopped + if (IsStopped(__FUNCTION__)) + { + return (false); + } + + // + // for hedging mode only + if (!IsHedging()) + { + return (false); + } + + // + // check position existence + if (!PositionSelectByTicket(ticket)) + { + return (false); + } + + // + string symbol = PositionGetString(POSITION_SYMBOL); + + // + // clean + ClearStructures(); + + // + // check filling + if (!FillingCheck(symbol)) + { + return (false); + } + + // + // check + if ((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + // + // prepare request for close BUY position + m_request.type = ORDER_TYPE_SELL; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_BID); + } + else + { + // + // prepare request for close SELL position + m_request.type = ORDER_TYPE_BUY; + m_request.price = SymbolInfoDouble(symbol, SYMBOL_ASK); + } + + // + // check volume + double position_volume = PositionGetDouble(POSITION_VOLUME); + if (position_volume > volume) + { + position_volume = volume; + } + + // + // setting request + m_request.action = TRADE_ACTION_DEAL; + m_request.position = ticket; + m_request.symbol = symbol; + m_request.volume = position_volume; + m_request.magic = m_magic; + m_request.deviation = (deviation == ULONG_MAX) ? m_deviation : deviation; + + // + // Specifieng Comment ... + m_request.comment = comment; + + // + // close position + return (OrderSend(m_request, m_result)); + } +}; + +// +// Implementation ... + +// +// a Class For Manage Trades and Handle Trading Actions ... +class XCTrade : public XCBase +{ + // + // Public ... + public: + // + // Props ... + XCAccount *mAccount; // Account Info Provider + + // + // Constructors ... + XCTrade( + int slippage, // Specify Slippage + ulong magicNumber, // Specify Magic Number + double maxAllowedSpread = 0, // Max Allowed Spred for Opening Trades + int maxAllowedPositions = 0, // Max Allowed Positions + double maxAllowedDrawdownFactor = 0 // Max Allowed Drawdown Factor + ) + { + // + // Setting Props ... + mSlippage = slippage; + mMagicNumber = magicNumber; + + // + mMaxAllowedSpread = maxAllowedSpread; + mMaxAllowedPositions = maxAllowedPositions; + mMaxAllowedDrawdownFactor = maxAllowedDrawdownFactor; + + // + mAccount = new XCAccount(); + + // + // Instance Base Trader Class ... + mTrader = new XCTradeBase(); + + // + // Configuring Base Trader Class ... + mTrader.SetAsyncMode(false); + mTrader.SetDeviationInPoints(mSlippage); + mTrader.SetExpertMagicNumber(mMagicNumber); + + // + // Setting Log Level ... + mTrader.LogLevel(LOG_LEVEL_ERRORS); + + // + // OnTrade Context ... + + // + mDaysForRead = 1; + mScanStarted = false; + + // + // Reset On Trade Counter ... + ResetOnTradeContext(); + + // + // Init On Trade Context ... + InitOnTradeContext(); + } + + // + // Deconstructor ... + ~XCTrade() + { + // + // Remove Pointer ... + delete mTrader; + delete mAccount; + + // + ZeroMemory(mTrader); + ZeroMemory(mAccount); + + // + Clean(mOnModifyEventHandlers); + Clean(mStopLossEventHandlers); + Clean(mTakeProfitEventHandlers); + Clean(mOnForceCloseEventHandlers); + Clean(mDealsChangedEventHandlers); + Clean(mOrdersChangedEventHandlers); + Clean(mOnPartialCloseEventHandlers); + Clean(mPositionsChangedEventHandlers); + Clean(mTradeStateChangedEventHandlers); + } + + // + // Props ... + + // + // Retrieve Slippage ... + int GetSlippage() + { + return mSlippage; + } + + // + // Retrieve Magic Number ... + ulong GetMagicNumber() + { + return mMagicNumber; + } + + // + double GetMaxAllowedSpread() + { + return mMaxAllowedSpread; + } + + // + int GetMaxAllowedPositions() + { + return mMaxAllowedPositions; + } + + // + void SetMaxAllowedPositions(int value) + { + // + if (value < 0) + { + value = 0; + } + + // + mMaxAllowedPositions = value; + } + + // + double GetMaxAllowedDrawdownFactor() + { + return mMaxAllowedDrawdownFactor; + } + + // + // Add Event Listeners ... + + // + void AddOnModifyPositionEventHandler(TOnModify handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnModifyEventHandlers + // + ); + } + + // + void AddOnForceClosePositionEventHandler(TOnForceClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnForceCloseEventHandlers + // + ); + } + + // + void AddOnPartialClosePositionEventHandler(TOnPartialClose handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnPartialCloseEventHandlers + // + ); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnTradeStateChangedEventHandler(TOnTradeStateChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTradeStateChangedEventHandlers + // + ); + } + + // + // Add New Deals Changed Event Handler ... + void AddOnDealsChangedEventHandler(TOnDealsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mDealsChangedEventHandlers + // + ); + } + + // + // Add New Orders Changed Event Handler ... + void AddOnOrdersChangedEventHandler(TOnOrdersChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOrdersChangedEventHandlers + // + ); + } + + // + // Add New Positions Changed Event Handler ... + void AddOnPositionsChangedEventHandler(TOnPositionsChanged handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mPositionsChangedEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnStopLossEventHandler(TOnStopLoss handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mStopLossEventHandlers + // + ); + } + + // + // Add New Stop Loss Event Handler ... + void AddOnTakeProfitEventHandler(TOnTakeProfit handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mTakeProfitEventHandlers + // + ); + } + + // + // Add New Signal Executed Event Handler ... + void AddOnSignalExecutedEventHandler(TOnSignal handler) + { + // + if (handler == NULL) + { + return; + } + + // + Add( + handler, + mOnSignalExecutedEventHandlers // + ); + } + + // + // Functions ... + + // + // Handlers ... + + // + // Process On Trade Requirement ... + // this Only Used when we Have to Proccess OnTrade Event in EA(s) ... + void HandleOnTradeEvent( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + result.Clean(); + + // + if (mScanStarted) + { + // + ProcessOnTradeContext(result); + } + else + { + // + // Init Trade Context ... + InitOnTradeContext(); + + // + return; + } + + // + // Here we Can Check the Start ... + bool isValid = + // + result.IsValid() && + // + !result.hasNewDeal && + !result.hasNewOrder && + !result.hasNewPosition && + !result.hasNewHistoryOrder + // + ; + if (!isValid) + { + return; + } + + // + // State ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(result); + + // + // Deals ... + if (result.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(result.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + int dealsCount = GetDeals(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // Orders ... + if (result.hasNewOrder || result.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(result.newOrders + result.newHistoryOrders); + } + + // + // Positions ... + if (result.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(result.newPositions); + } + } + + // + // This Must be Called Every time OnTrade Event Happening ... + // this Used for Implementing Custom Senarios ... + XOnTradeHandlerState HandleOnTrade() + { + // + // Handle OnTrade Event ... + XOnTradeHandlerState state; + HandleOnTradeEvent(state); + if ( + !state.hasNewDeal && + !state.hasNewOrder && + !state.hasNewPosition && + !state.hasNewHistoryOrder) + { + return state; + } + + // + // State ... + + // + // Notfy Trade State Changed Event ... + NotifyTradeStateChangeEvent(state); + + // + // DEALS ... + if (state.hasNewDeal) + { + // + // Notfy Deals Changed Event ... + NotifyDealsChangeEvent(state.newDeals); + + // + // Retrieve Last Deal ... + XDeal deals[]; + GetDeals(deals); + int dealsCount = ArraySize(deals); + if (dealsCount > 0) + { + // + XDeal lastDeal = deals[0]; + + // + if (lastDeal.reason == DEAL_REASON_TP) + { + NotifyTakeProfitEvent(lastDeal); + } + else if (lastDeal.reason == DEAL_REASON_SL) + { + NotifyStopLossEvent(lastDeal); + } + } + } + + // + // ORDERS ... + if (state.hasNewOrder || state.hasNewHistoryOrder) + { + // + // Notfy Orders Changed Event ... + NotifyOrdersChangeEvent(state.newOrders + state.newHistoryOrders); + } + + // + // POSITIONS ... + if (state.hasNewPosition) + { + // + // Notfy Positions Changed Event ... + NotifyPositionsChangeEvent(state.newPositions); + } + + // + return state; + } + + // + // Trade Actions ... + + // + // Main ... + + // + // Policies ... + + // + // Check Acocunt Balance is Allow new Trades or not ... + bool CheckEquityForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedDrawdownFactor <= 0) + { + // + result = true; + return result; + } + + // + double equity = mAccount.GetEquity(); + double balance = mAccount.GetBalance(); + + // + double selectedBalance = MathMax(equity, balance) - MathMin(equity, balance); + + // + double maxAllowedBalanceDrawDown = GetMaxAllowedEquity(); + + // + result = equity > balance || + (equity <= balance && + selectedBalance <= maxAllowedBalanceDrawDown); + + // + return result; + } + + // + // Check Max Allowed Positions Policy for Trade ... + bool CheckPositionsForTrade() + { + // + bool result = false; + + // + if (mMaxAllowedPositions <= 0) + { + // + result = true; + return result; + } + + // + XPosition positions[]; + int positionsCount = GetPositions(positions); + if (positionsCount <= 0) + { + // + result = true; + return result; + } + + // + result = positionsCount < mMaxAllowedPositions; + + // + return result; + } + + // + // Check Spread is Ok for Executing Specific Signal ... + bool CheckSpreadForSignalExecution(XSignal &mSignal) + { + // + bool result = false; + + // + bool isSpreadCheckEnable = mMaxAllowedSpread > 0; + if (!isSpreadCheckEnable) + { + result = true; + } + else + { + // + // Retrieve Signal Spread ... + double spread = GetSpread(mSignal.symbol); + result = spread <= mMaxAllowedSpread; + } + + // + return result; + } + + // + // Check Account Policy ... + bool CheckAccountPolicy( + XSignal &mSignal, // For Executing Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &state // State Holder + ) + { + // + bool result = false; + + // + // Check Positions For Trade ... + result = CheckPositionsForTrade(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_MAX_REACHED; + return result; + } + + // + // Check Equity For Trade ... + result = CheckEquityForTrade(); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_NO_EQUITY; + return result; + } + + // + // Check Spread for Trade ... + result = CheckSpreadForSignalExecution(mSignal); + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_SPREAD; + return result; + } + + // + return result; + } + + // + // Execute a Signal ... + bool ExecuteSignal( + XSignal &mSignal, // Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &state, // Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL, // order expiration time + bool checkPolicies = true // Check Account Policies + ) + { + // + bool result = false; + state = X_SIGNAL_EXECUTION_UNKNOWN; + + // + double currentEntry = GetEntry( + mSignal.symbol, + mSignal.type + // + ); + bool isLong = IsLong(mSignal.type); + + // + if (!mSignal.IsValid()) + { + // + state = X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS; + return result; + } + + // + // Prepare Signal Comment ... + string mSComment = mSignal.GenerateComment(); + if (!Contains(mSComment, mSignal.comment)) + { + mSignal.comment += mSComment; + } + + // + // Handle Market Execution ... + if (mSignal.mode == X_ORDER_MODE_MARKET) + { + // + // Do Apply Policies here ... + bool hasPolicy = !checkPolicies + ? true + : CheckAccountPolicy(mSignal, state); + if (!hasPolicy) + { + result = false; + } + else + { + // + if (isLong) + { + // + result = Buy( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + mSignal.comment + // + ); + } + else + { + // + result = Sell( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + mSignal.comment + // + ); + } + } + } + // + // Handle Stop Execution ... + else if (mSignal.mode == X_ORDER_MODE_STOP) + { + + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? mSignal.entry > currentEntry + : mSignal.entry < currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyStop( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + else + { + // + result = SellStop( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + } + // + // Handle Limit Execution ... + else if (mSignal.mode == X_ORDER_MODE_LIMIT) + { + // + // Check Conditions ... + + // + // Check Price ... + result = isLong + ? mSignal.entry < currentEntry + : mSignal.entry > currentEntry; + if (!result) + { + // + state = X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR; + return result; + } + + // + // Execute Order ... + if (isLong) + { + // + result = BuyLimit( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + else + { + // + result = SellLimit( + mSignal.symbol, + mSignal.period, + mSignal.volume, + mSignal.entry, + mSignal.sl, + mSignal.tp, + lifetime, + expiration, + mSignal.comment + // + ); + } + } + + // + // Handle Ticket ... + if (result) + { + // + state = X_SIGNAL_EXECUTION_SUCCEED; + + // + ulong ticket; + if (mSignal.mode == X_ORDER_MODE_MARKET) + { + ticket = GetLastOpenPositionTicket(); + } + else + { + ticket = GetLastPlacedOrderTicket(); + } + + // + mSignal.positionId = ticket; + + // + // Notify Signal Execution ... + if (mSignal.mode == X_ORDER_MODE_MARKET) + { + NotifySignalExecuted(mSignal); + } + } + + // + return result; + } + + // + // Execute a Collection Of Signals ... + int ExecuteSignals( + XSignal &signals[], // Collection of Signal for Execution + ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL, // order expiration time + bool checkPolicies = true // Check Account Policies + ) + { + // + int result = 0; + + // + Clean(states); + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + ArrayResize(states, signalsCount); + ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN); + for (int i = 0; i < signalsCount; i++) + { + // + bool isExecuted = ExecuteSignal( + signals[i], + states[i], + lifetime, + expiration, + checkPolicies + // + ); + + // + if (isExecuted) + { + result++; + } + } + + // + return result; + } + + // + int ExecuteSpecifiedSignals( + XSignal &signals[], // Collection of Signal for Execution + XSignal ¬Executeds[], // Not Executed Signal + ENUM_X_SIGNAL_EXECUTION_RESULT &states[], // Signal Execution Result + ENUM_ORDER_TYPE_TIME lifetime = ORDER_TIME_GTC, // Order LifeTime + datetime expiration = NULL, // order expiration time + bool checkPolicies = true // Check Account Policies + ) + { + // + int result = 0; + + // + Clean(states); + Clean(notExecuteds); + + // + int signalsCount = ArraySize(signals); + if (signalsCount <= 0) + { + return result; + } + + // + ArrayResize(states, signalsCount); + ArrayInitialize(states, X_SIGNAL_EXECUTION_UNKNOWN); + for (int i = 0; i < signalsCount; i++) + { + // + bool isExecuted = ExecuteSignal( + signals[i], + states[i], + lifetime, + expiration + // + ); + + // + if (isExecuted) + { + result++; + } + else + { + // + AddRef( + signals[i], + notExecuteds // + ); + } + } + + // + return result; + } + + // + // Regular Trade Actions ... + + // + // Buy ... + + // + // Force Open a Buy/Long Position ... + bool Buy( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.Buy( + volume, + symbol, + price, + sl, + tp, + comment + // + ); + + // + return result; + } + + // + // Send BUY LIMIT order ... + bool BuyLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.BuyLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Send BUY STOP order ... + bool BuyStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.BuyStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Sell ... + + // + // Force Open a Sell/Short Position ... + bool Sell( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // position volume + double price, // execution price + double sl = 0, // stop loss price + double tp = 0, // take profit price + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.Sell( + volume, + symbol, + price, + sl, + tp, + comment + // + ); + + // + return result; + } + + // + // Send SELL LIMIT order ... + bool SellLimit( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.SellLimit( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Send SELL STOP order ... + bool SellStop( + string symbol, // Specified Symbol + ENUM_TIMEFRAMES period, // Specified Trade's Period + double volume, // order volume + double price, // order price + double sl = 0.0, // stop loss price + double tp = 0.0, // take profit price + ENUM_ORDER_TYPE_TIME typeTime = ORDER_TIME_GTC, // order lifetime + datetime expiration = 0, // order expiration time + string comment = NULL // comment + ) + { + // + bool result = false; + + // + ENUM_TIMEFRAMES mPeriod = ExtractPeriod(comment); + if (!IsValid(comment) || + !IsValid(mPeriod)) + { + // + string mPeriodStr = GeneratePeriodTag(period); + + // + comment += mPeriodStr; + } + + // + result = mTrader.SellStop( + volume, + price, + symbol, + sl, + tp, + typeTime, + expiration, + comment + // + ); + + // + return result; + } + + // + // Check a Position is Exists Open or not ... + bool IsOpen( + ulong ticket // Specified Position Ticket + ) + { + // + bool result = false; + + // + result = mPositionInfo + .SelectByTicket(ticket); + + // + return result; + } + + // + // Modify Position ... + bool Modify( + const ulong ticket, // position ticket + double sl = 0, // stop loss price + double tp = 0, // take profit + string comment = NULL // comment + ) + { + // + bool result = false; + + // + // Validate Args ... + XPosition position; + result = + GetPosition( + ticket, + position // + ) && + (tp >= 0 || sl >= 0); + if (!result) + { + return result; + } + + // + // Use Position Comment when there isn't new One ... + if (!IsValid(comment) == 0) + { + // + // if there isn't provided Comment + // Use Position Comment for default ... + comment = "Modify " + GetPositionComment(ticket); + } + + // + result = mTrader.PositionModify( + ticket, + sl, + tp, + comment + // + ); + if (result) + { + // + NotifyModifyEvent( + ticket, + position.profit, + comment // + ); + } + + // + return result; + } + + // + // Close Position By Ticket ... + bool Close( + ulong ticket, // Position Ticket + string comment = NULL // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + // Check Position Open ... + XPosition position; + result = GetPosition( + ticket, + position // + ); + if (!result) + { + return result; + } + + // + // Use Default Position Comment if it's Not Provided ... + if (!IsValid(comment)) + { + comment = "Close " + GetPositionComment(ticket); + } + + // + // Close Position By Specific Comment ... + result = mTrader.PositionClose( + ticket, + mSlippage, + comment + // + ); + if (result) + { + // + NotifyForceCloseEvent( + ticket, + position, + comment // + ); + } + + // + return result; + } + + // + // Close Specified Positions ... + int Close( + string comment = NULL, // Close Position By Specific Comment + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions + ) + { + // + int result = 0; + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment + // + ); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Close a Collection of Positions ... + int Close( + XPosition &positions[], // Collection of Positions + string comment = NULL // Close Comment + ) + { + // + int result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isClosed = Close( + iPosition.ticket, + comment + // + ); + if (isClosed) + { + result++; + } + } + + // + return result; + } + + // + // Close Partial By Ticket ... + bool ClosePartial( + ulong ticket, // Position Ticket + double volume, // Volume Size for Partial Closing + string comment = NULL // Close Position By Specific Comment + ) + { + // + bool result = false; + + // + XPosition position; + result = GetPosition( + ticket, + position // + ); + if (!result) + { + return result; + } + + // + // Use Default Partial Close Comment ... + if (!IsValid(comment)) + { + // + comment += "PClose " + GetPositionComment(ticket); + } + + // + result = mTrader.PositionClosePartial( + ticket, + volume, + mSlippage, + comment + // + ); + if (result) + { + // + NotifyPartialCloseEvent( + ticket, + position.profit, + comment // + ); + } + + // + return result; + } + + // + // Cancel Specific Order ... + bool CancelOrder(ulong ticket) + { + return mTrader + .OrderDelete(ticket); + } + + // + // Cancel Specific Orders ... + int CancelOrders( + XOrder &orders[] // Specified Orders ... + ) + { + // + int result = 0; + + // + int ordersCount = ArraySize(orders); + if (ordersCount <= 0) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + bool isDeleted = mTrader + .OrderDelete(iOrder.ticket); + if (isDeleted && !result) + { + result++; + } + } + + // + return result; + } + + // + // Extractors ... + + // + // Positions ... + + // + // Calculate Positions Profit ... + double Profit( + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true // Get Only Self Open Positions + ) + { + // + double result = 0; + + // + // Retrieve Positions ... + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic + // + ); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + result += positions[i].profit; + } + + // + return result; + } + + // + // Retrieve Specific Position by Index ... + bool GetPositionByIndex( + int index, // Specified Index + XPosition &result // Hold's Result + ) + { + // + bool isInited = result + .ByIndex(index); + + // + return isInited; + } + + // + // Retrieve Specific Position by Ticket ... + bool GetPosition( + ulong ticket, // Specified Ticket + XPosition &result // Hold's Result + ) + { + // + bool isInited = result + .ByTicket(ticket); + + // + return isInited; + } + + // + double GetPositionCommission( + ulong ticket // Specified Ticket + ) + { + // + double result = 0; + + // + XPosition position; + bool hasPosition = GetPosition( + ticket, + position // + ); + if (!hasPosition) + { + return result; + } + + // + XDeal deals[]; + int dealsCount = GetDeals( + deals, + position.symbol, + position.provider, + position.period, + NULL, + DEAL_ENTRY_IN // + ); + if (IsValidSize(dealsCount)) + { + // + for (int i = 0; i < dealsCount; i++) + { + // + XDeal iDeal = deals[i]; + if (iDeal.positionId == ticket) + { + // + result = iDeal.commission; + break; + } + } + } + + // + return result; + } + + // + // Retrieve Positions ... + int GetPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = PositionsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XPosition iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + void GetPositions( + XPosition &longs[], // Hold's Longs Result + XPosition &shorts[], // Hold's Shorts Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + // Retrieve Long Positions ... + GetPositions( + longs, + symbol, + provider, + period, + X_POSITION_TYPE_LONG, + filterByMagic, + forceClean // + ); + + // + // Retrieve Short Positions ... + GetPositions( + shorts, + symbol, + provider, + period, + X_POSITION_TYPE_SHORT, + filterByMagic, + forceClean // + ); + } + + // + // Select In Profit Positions ... + int GetInProfitPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit <= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Select In Drawdown Positions ... + int GetInDrawdownPositions( + XPosition &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_X_POSITION_SELECT_METHODS method = NULL, // Selection Method + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + XPosition positions[]; + int positionsCount = GetPositions( + positions, + symbol, + provider, + period, + type, + filterByMagic, + forceClean); + if (positionsCount <= 0) + { + return mResult; + } + + // + XPosition min; + XPosition max; + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit >= 0) + { + continue; + } + + // + // Calculate Min and Max ... + + // + // Min ... + if (!min.IsValid() || min.profit <= 0 || min.profit > iPosition.profit) + { + min = iPosition; + } + + // + // Max ... + if (!max.IsValid() || max.profit <= 0 || max.profit < iPosition.profit) + { + max = iPosition; + } + + // + bool isSelectionMethodFilterPassed = + // + (method == NULL || + method == X_POSITION_SELECT_ALL) + ? true + : false; + // + ; + if (!isSelectionMethodFilterPassed) + { + continue; + } + + // + AddRef( + iPosition, + result + // + ); + } + + // + if (min.IsValid() && + (method == X_POSITION_SELECT_MIN || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + min, + result + // + ); + } + + // + if (max.IsValid() && + (method == X_POSITION_SELECT_MAX || + method == X_POSITION_SELECT_BOTH)) + { + // + AddRef( + max, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Orders ... + + // + // Retrieve Specific Order by Index ... + bool GetOrder( + int index, // Specified Index + XOrder &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + // Retrieve Specific Positions Orders ... + int GetOrders( + ulong ticket, // Positions Ticket + XOrder &result[], // Hold's Result + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + // Select History by Specified Ticket ... + bool isHistorySelected = HistorySelectByPosition(ticket); + if (!isHistorySelected) + { + return mResult; + } + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder; + bool isLoaded = iOrder.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + bool isTicketFilterPassed = + // + iOrder.ticket = ticket + // + ; + if (!isTicketFilterPassed) + { + continue; + } + + // + AddRef( + iOrder, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve All Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Retrieve Historical Orders ... + int GetOrders( + XOrder &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_X_POSITION_TYPES type = NULL, // Long (Buy) or Short (Sell) + ENUM_ORDER_STATE state = NULL, // Order State + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = OrdersTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XOrder iItem; + bool isLoaded = iItem.HistoryByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + state, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Deals ... + + // + // Retrieve Specific Deal by Index ... + bool GetDeal( + int index, // Specified Index + XDeal &result // Hold's Result + ) + { + // + return result + .ByIndex(index); + } + + // + bool GetLastDeal( + XDeal &result // Hold's Result + ) + { + // + bool mResult = false; + + // + mResult = HistorySelect(0, TimeCurrent()); + if (!mResult) + { + return mResult; + } + + // + int lastDealIndex = HistoryDealsTotal() - 1; + + // + mResult = GetDeal( + lastDealIndex, + result // + ); + + // + return mResult; + } + + // + // Retrieve Specified Deal's History ... + int GetDealsHistory( + XDeal &deal, // Specified Deal + XOrder &history[], // Deals History + bool forceClean = true // Clean Result Array + ) + { + // + int result = 0; + + // + if (!deal.IsValid()) + { + return result; + } + + // + result = GetOrders( + deal.positionId, + history, + forceClean); + + // + return result; + } + + // + // Retrieve All Deals ... + int GetDeals( + XDeal &result[], // Hold's Result + string symbol = NULL, // Trading Symbol + string provider = NULL, // Signal Provider + ENUM_TIMEFRAMES period = NULL, // Trading Period + ENUM_DEAL_TYPE type = NULL, // Deal Type + ENUM_DEAL_ENTRY entry = NULL, // Deal Entry + ENUM_DEAL_REASON reason = NULL, // Deal Reason + datetime startDate = NULL, // Specify Start Date + datetime endDate = NULL, // Specify End Date + bool filterByMagic = true, // Get Only Self Open Positions + bool forceClean = true // Clean Result Array + ) + { + // + int mResult = 0; + + // + endDate = NormalizeTime(endDate); + + // + if (!IsValid(startDate)) + { + startDate = endDate - PeriodSeconds(PERIOD_D1); + } + + // + bool isHistorySelected = HistorySelect( + startDate, + endDate); + if (!isHistorySelected) + { + return mResult; + } + + // + int before = ArraySize(result); + + // + if (forceClean) + { + Clean(result); + } + + // + // Count Positions ... + int itemsCount = HistoryDealsTotal(); + if (itemsCount <= 0) + { + return mResult; + } + + // + // Loop Through all Positions ... + for (int i = itemsCount - 1; i >= 0; i--) + { + // + XDeal iItem; + bool isLoaded = iItem.ByIndex(i); + if (!isLoaded) + { + continue; + } + + // + // Now we have to Check Given Filters ... + bool isFiltersPassed = + iItem.IsFiltersPassed( + symbol, + provider, + period, + type, + entry, + reason, + mMagicNumber, + filterByMagic + // + ); + if (!isFiltersPassed) + { + continue; + } + + // + // Add Filtered Item into Result ... + AddRef( + iItem, + result + // + ); + } + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; + } + + // + // Support Functions ... + + // + // Check a Position has Support or not ... + bool HasSupport( + ulong ticket, + bool forceOpen = true // + ) + { + // + bool result = false; + + // + result = ticket > 0; + if (!result) + { + return result; + } + + // + if (forceOpen) + { + // + result = IsOpen(ticket); + if (!result) + { + return result; + } + } + + // + XPosition positions[]; + int positionsCount = GetPositions(positions); + result = IsValidSize(positionsCount); + if (!result) + { + return result; + } + + // + // Extract Support Positions ... + XPosition supports[]; + int supportsCount = ExtractSupports( + positions, + supports // + ); + result = IsValidSize(supportsCount); + if (!result) + { + return result; + } + + // + // Loop Through Supports ... + for (int i = 0; i < supportsCount; i++) + { + // + XPosition iSupport = supports[i]; + + // + ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); + ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); + + // + result = + // + (supportedTicket > 0 && ticket == supportedTicket) + // + || + // + (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) + // + ; + if (result) + { + break; + } + } + + // + return result; + } + + // + // Retrieve Specific Position's Supports ... + int GetSupports( + ulong ticket, + XPosition &dest[], // Result ... + bool forceOpen = true // + ) + { + // + int result = 0; + + // + Clean(dest); + + // + bool hasSupport = HasSupport( + ticket, + forceOpen // + ); + if (!hasSupport) + { + return result; + } + + // + XPosition positions[]; + int positionsCount = GetPositions(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + // Extract Support Positions ... + XPosition supports[]; + int supportsCount = ExtractSupports( + positions, + supports // + ); + if (!IsValidSize(supportsCount)) + { + return result; + } + + // + // Loop Through Supports ... + for (int i = 0; i < supportsCount; i++) + { + // + XPosition iSupport = supports[i]; + + // + ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); + ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); + + // + bool isOwn = + // + (supportedTicket > 0 && ticket == supportedTicket) + // + || + // + (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) + // + ; + if (isOwn) + { + // + AddRef( + iSupport, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Retrieve Specific Position's Supports ... + int GetSupports( + ulong ticket, + XOrder &dest[], // Result ... + bool forceOpen = true // + ) + { + // + int result = 0; + + // + Clean(dest); + + // + bool hasSupport = HasSupport( + ticket, + forceOpen // + ); + if (!hasSupport) + { + return result; + } + + // + XOrder orders[]; + int ordersCount = GetOrders( + orders, + NULL, // All Symbols ... + NULL, // All Providers ... + NULL, // All Periods ... + X_POSITION_TYPE_ALL, // All Types ... + ORDER_STATE_PLACED, // Untriggere Orders ... + true // + ); + if (!IsValidSize(ordersCount)) + { + return result; + } + + // + // Extract Support Positions ... + XOrder supports[]; + int supportsCount = ExtractSupports( + orders, + supports // + ); + if (!IsValidSize(supportsCount)) + { + return result; + } + + // + // Loop Through Supports ... + for (int i = 0; i < supportsCount; i++) + { + // + XOrder iSupport = supports[i]; + + // + ulong supportedTicket = ExtractSupportedTicket(iSupport.comment); + ulong eqmSupportedTicket = ExtractEQMSupportedTicket(iSupport.comment); + + // + bool isOwn = + // + (supportedTicket > 0 && ticket == supportedTicket) + // + || + // + (eqmSupportedTicket > 0 && ticket == eqmSupportedTicket) + // + ; + if (isOwn) + { + // + AddRef( + iSupport, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; + } + + // + // Tools ... + + // + // Retrieve Last Open Position Ticket ... + ulong GetLastOpenPositionTicket() + { + // + ulong result = 0; + + int positionsCount = PositionsTotal(); + if (positionsCount <= 0) + { + return result; + } + + // + result = PositionGetTicket(PositionsTotal() - 1); + + // + return result; + } + + // + // Retrieve Last Placed Order Ticket ... + ulong GetLastPlacedOrderTicket() + { + // + ulong result = 0; + + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + if (mOrderInfo.SelectByIndex(ordersCount - 1)) + { + result = mOrderInfo.Ticket(); + } + + // + return result; + } + + // + // Prepare Dynamic Volume ... + double GetDynamicVolume( + string _symbol, + double _balanceFactor, + double _volumeStep // + ) + { + // + double result = 0; + + // + // Validate Inputs ... + if (!IsValid(_symbol) || + _volumeStep <= 0 || + _balanceFactor <= 0) + { + return result; + } + + // + // Retrieve Account Balance ... + double balance = mAccount.GetBalance(); + + // + double bStep = balance / _balanceFactor; + bStep = MathFloor(bStep); + if (bStep == 0) + { + bStep = 1; + } + + // + result = bStep * _volumeStep; + + // + result = NormalizeVolume( + result, + _symbol // + ); + + // + return result; + } + + // + // Protected ... + protected: + // + // Props ... + + // + // Event Listener Notifiers ... + + // + // State ... + void NotifyTradeStateChangeEvent(const XOnTradeHandlerState &state) + { + // + int count = ArraySize(mTradeStateChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTradeStateChanged iHandler = mTradeStateChangedEventHandlers[i]; + iHandler(state); + } + } + + // + // Deals ... + void NotifyDealsChangeEvent(int changes) + { + // + int count = ArraySize(mDealsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnDealsChanged iHandler = mDealsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // Orders ... + void NotifyOrdersChangeEvent(int changes) + { + // + int count = ArraySize(mOrdersChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnOrdersChanged iHandler = mOrdersChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // Positions ... + void NotifyPositionsChangeEvent(int changes) + { + // + int count = ArraySize(mPositionsChangedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnPositionsChanged iHandler = mPositionsChangedEventHandlers[i]; + iHandler(changes); + } + } + + // + // StopLoss ... + void NotifyStopLossEvent(const XDeal &deal) + { + // + int count = ArraySize(mStopLossEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnStopLoss iHandler = mStopLossEventHandlers[i]; + iHandler(deal); + } + } + + // + // Take Profit ... + void NotifyTakeProfitEvent(const XDeal &deal) + { + // + int count = ArraySize(mTakeProfitEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnTakeProfit iHandler = mTakeProfitEventHandlers[i]; + iHandler(deal); + } + } + + // + void NotifyModifyEvent( + ulong ticket, + double profit, + string comment // + ) + { + // + int count = ArraySize(mOnModifyEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnModify iHandler = mOnModifyEventHandlers[i]; + iHandler( + ticket, + profit, + comment // + ); + } + } + + // + void NotifyForceCloseEvent( + ulong ticket, + XPosition &position, + string comment // + ) + { + // + int count = ArraySize(mOnForceCloseEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnForceClose iHandler = mOnForceCloseEventHandlers[i]; + iHandler( + ticket, + position, + comment // + ); + } + } + + // + void NotifyPartialCloseEvent( + ulong ticket, + double profit, + string comment // + ) + { + // + int count = ArraySize(mOnPartialCloseEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnModify iHandler = mOnPartialCloseEventHandlers[i]; + iHandler( + ticket, + profit, + comment // + ); + } + } + + // + void NotifySignalExecuted(XSignal &signal) + { + // + bool has = signal.IsValid() && + signal.IsExecuted(); + if (!has) + { + return; + } + + // + int count = ArraySize(mOnSignalExecutedEventHandlers); + if (count <= 0) + { + return; + } + + // + for (int i = 0; i < count; i++) + { + // + TOnSignal iHandler = mOnSignalExecutedEventHandlers[i]; + iHandler(signal); + } + } + + // + // Tools ... + + // + // Retrieve Specified Position Comment ... + string GetPositionComment(ulong ticket) + { + // + string result = NULL; + + // + if (!IsOpen(ticket)) + { + return result; + } + + // + XPosition position; + bool isLoaded = position.ByTicket(ticket); + if (!isLoaded) + { + return result; + } + + // + result = position.comment; + + // + return result; + } + + // + ENUM_TIMEFRAMES GetDealPeriod(XDeal &deal) + { + // + ENUM_TIMEFRAMES result = NULL; + + // + XOrder orders[]; + int ordersCount = GetDealsHistory( + deal, + orders); + if (!ordersCount) + { + return result; + } + + // + for (int i = 0; i < ordersCount; i++) + { + // + XOrder iOrder = orders[i]; + + // + if (IsValid(iOrder.comment)) + { + // + ENUM_TIMEFRAMES iPeriod = ExtractPeriod(iOrder.comment); + if (IsValid(iPeriod)) + { + result = iPeriod; + break; + } + } + } + + // + return result; + } + + // + double GetMaxAllowedEquity() + { + // + double equity = mAccount.GetEquity(); + double balance = mAccount.GetBalance(); + + // + double balanceForFactor = MathAbs(equity - balance); + if (balanceForFactor <= 0) + { + balanceForFactor = balance; + } + else + { + balanceForFactor = equity; + } + + // + double result = balanceForFactor * mMaxAllowedDrawdownFactor; + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + int mSlippage; // Slippage ... + ulong mMagicNumber; // Magic Number (Unique Identifier) ... + + // + double mMaxAllowedSpread; // Max Allowed Spred for Opening Trades + int mMaxAllowedPositions; // Max Allowed Same Positions + double mMaxAllowedDrawdownFactor; // Max Allowed Drawdown Factor + + // + XCTradeBase *mTrader; // Base CTrade Manipulated Instance ... + + // + CDealInfo mDealInfo; // Deals Info ... + COrderInfo mOrderInfo; // Order Info ... + CPositionInfo mPositionInfo; // Positions Info + CHistoryOrderInfo mHistoryOrderInfo; // History Orders Info ... + + // + // Position Info Collector ... + + // + // Tools ... + + // + // OnTrade Event Handlers Section ... + + // + // Props ... + + // + int mDaysForRead; // Reading Dates for Trade History Checker ... + datetime mEndDate; // End Date for Trade history Checking ... + datetime mStartDate; // Start Date for Trade history Checking ... ... + int mOrdersCount; // Number of Active orders ... + int mPositionsCount; // Number of Open positions ... + int mDealsCount; // Number of Deals in the Trade History Checking ... + int mHistoryOrdersCount; // Number of Orders in the Trade History Checking ... + bool mScanStarted; // a Flag of counter relevance ... + + // + // Event Listeners ... + + // + // Deals Changed Event Handlers ... + TOnDealsChanged mDealsChangedEventHandlers[]; + + // + // Orders Changed Event Handlers ... + TOnOrdersChanged mOrdersChangedEventHandlers[]; + + // + // Positions Changed Event Handlers ... + TOnPositionsChanged mPositionsChangedEventHandlers[]; + + // + // Trade State Changed Event Handlers ... + TOnTradeStateChanged mTradeStateChangedEventHandlers[]; + + // + // Signal Executed Event Handlers ... + TOnSignal mOnSignalExecutedEventHandlers[]; + + // + TOnModify mOnModifyEventHandlers[]; + TOnForceClose mOnForceCloseEventHandlers[]; + TOnPartialClose mOnPartialCloseEventHandlers[]; + + // + // TPSL ... + TOnStopLoss mStopLossEventHandlers[]; + TOnTakeProfit mTakeProfitEventHandlers[]; + + // + // Reset On Trade Scanner Context ... + void ResetOnTradeContext() + { + // + mEndDate = TimeCurrent(); + mStartDate = mEndDate - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + } + + // + // Initial Context Of Trade Scanner ... + void InitOnTradeContext() + { + // + ResetLastError(); + + // + mOrdersCount = OrdersTotal(); + mPositionsCount = PositionsTotal(); + + // + // load history ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current value ... + mDealsCount = HistoryDealsTotal(); + mHistoryOrdersCount = HistoryOrdersTotal(); + + // + mScanStarted = true; + } + + // + // Check Statrt Date In Trade History ... + void CheckStartDateInTradeHistory() + { + // + // initial interval, if we were to start working right now .. + datetime currStart = TimeCurrent() - (mDaysForRead * PeriodSeconds(PERIOD_D1)); + + // + // make sure that the start limit of the trade history has not gone + // more than 1 day over the intended date ... + if (currStart - mStartDate > PeriodSeconds(PERIOD_D1)) + { + // + // correct the start date of history to be loaded in the cache ... + mStartDate = currStart; + + // + // now reload the trade history for the updated interval ... + HistorySelect(mStartDate, mEndDate); + + // + // correct the deal and order counters in history for further comparison + mHistoryOrdersCount = HistoryOrdersTotal(); + mDealsCount = HistoryDealsTotal(); + } + } + + // + // Process On Trade Context ... + void ProcessOnTradeContext( + XOnTradeHandlerState &result // Hold's Result + ) + { + // + mEndDate = TimeCurrent(); + + // + ResetLastError(); + + // + // download trading history from the specified interval to the program cache ... + bool selected = HistorySelect(mStartDate, mEndDate); + if (!selected) + { + return; + } + + // + // get the current values ... + int currOrders = OrdersTotal(); + int currPositions = PositionsTotal(); + int currDeals = HistoryDealsTotal(); + int currHistoryOrders = HistoryOrdersTotal(); + + // + // Orders ... + // check if the number of active orders has been changed ... + if (currOrders != mOrdersCount) + { + // + // number of active orders has been changed ... + result.hasNewOrder = true; + result.newOrders = currOrders - mOrdersCount; + + // + // update the value ... + mOrdersCount = currOrders; + } + + // + // Positions ... + // changes in the number of open positions ... + if (currPositions != mPositionsCount) + { + // + // number of open positions has been changed ... + result.hasNewPosition = true; + result.newPositions = currPositions - mPositionsCount; + + // + // update the value ... + mPositionsCount = currPositions; + } + + // + // Deals ... + // changes in the number of deals in the trade history cache ... + if (currDeals != mDealsCount) + { + // + // number of deals in the trade history cache has been changed ... + result.hasNewDeal = true; + result.newDeals = currDeals - mDealsCount; + + // + // update the value ... + mDealsCount = currDeals; + } + + // + // History Orders ... + // changes in the number of history orders in the trade history cache ... + if (currHistoryOrders != mHistoryOrdersCount) + { + // + // number of history orders in the trade history cache has been changed ... + result.hasNewHistoryOrder = true; + result.newHistoryOrders = currHistoryOrders - mHistoryOrdersCount; + + // + // update the value ... + mHistoryOrdersCount = currHistoryOrders; + } + + // + // checking if it is necessary to change the limits of the trade history to be requested in cache ... + CheckStartDateInTradeHistory(); + } +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Classes\x-saherelm.x-volume.class.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Class Library +// -------------------------------------- +// Name: XCVolume +// Description: provides all Requirements for Volume Managing ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Template Variables of Inputs for Using ... +// input group "Volume"; +// input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_STATIC; // Volume Applying Type +// input double eaStaticVoluem = X_MIN_VOLUME; // Static Volume +// input double eaDynamicVolumeStepBalance = 0.0; // Step of Balance for Increase Volume +// input double eaDynamicVolumeStepVolume = X_MIN_VOLUME; // Step of Volume Increasing +// input double eaConstantRiskBalance = 0.0; // Constant Risk Balance per Trade +// input double eaConstantPercent = 0.0; // Constant Percent of Balance Per Trade +// input double eaConstantBalance = 0.0; // Constant Balance for Calculations +// XCVolume *eaVolume; +// eaVolume = new XCVolume(); +// bool result = eaVolume.Init( +// eaVolumeSelect, +// eaStaticVoluem, +// eaDynamicVolumeStepBalance, +// eaDynamicVolumeStepVolume, +// eaConstantRiskBalance, +// eaConstantPercent, +// eaConstantBalance // +// ); +// if (!result) { +// return INIT_FAILED; +// } + +// +// Imports ... +#include "../Classes/x-saherelm.x-account.class.mq5" +#include "../Libraries/x-saherelm.x-trade.lib.mq5" + +// +// Definitions ... +#define X_MIN_VOLUME 0.01 + +// +enum ENUM_X_VOLUME_SELECT_TYPE +{ + X_VOLUME_NONE, // None + X_VOLUME_STATIC, // Static Volume + X_VOLUME_CURRENT, // Current Balance + X_VOLUME_EQUITY, // Current Equity + X_VOLUME_CONSTANT // Constant Value +}; + +// +bool IsValid(ENUM_X_VOLUME_SELECT_TYPE value) +{ + // + bool result = false; + + // + result = value != X_VOLUME_NONE; + + // + return result; +} + +// +string ToString(ENUM_X_VOLUME_SELECT_TYPE value) +{ + // + string result = NULL; + + // + result = EnumToString(value); + + // + return result; +} + +// +// Implementation ... +class XCVolume : public XCBase +{ + // + // Public ... + public: + // + // Props ... + XCAccount *account; + + // + // Constructor ... + XCVolume() + { + // + account = new XCAccount(); + + // + Default(); + } + + // + // Deconstructor ... + ~XCVolume() + { + // + ZeroMemory(account); + } + + // + bool Init( + ENUM_X_VOLUME_SELECT_TYPE _SelectType, + double _StaticVolume, + double _DynamicVolumeStepBalance, + double _DynamicVolumeStepVolume, + double _ConstantRiskBalance, + double _ConstantPercent, + double _ConstantBalance // + ) + { + // + bool result = false; + + // + mVolumeType = _SelectType; + mStaticVolume = _StaticVolume; + mConstantPercent = _ConstantPercent; + mConstantBalance = _ConstantBalance; + mConstantRiskBalance = _ConstantRiskBalance; + mDynamicVolumeStepVolume = _DynamicVolumeStepVolume; + mDynamicVolumeStepBalance = _DynamicVolumeStepBalance; + + // + result = + // + CanUseStaticVolume() || + CanUseDynamicVolume() || + CanUseConstantRiskBalance() || + CanUseConstantBalancePercent() + // + ; + + // + return result; + } + + // + // Prperties ... + + /** + * Get Volume Calculating Method ... + * + * @return (ENUM_X_VOLUME_SELECT_TYPE) + */ + ENUM_X_VOLUME_SELECT_TYPE VolumeType() + { + return mVolumeType; + } + + /** + * Set Volume Calculating Method ... + * + * @param value: ENUM_X_VOLUME_SELECT_TYPE member ... + */ + void VolumeType(ENUM_X_VOLUME_SELECT_TYPE value) + { + mVolumeType = value; + } + + /** + * Get Static Volume ... + * + * @return ( double ) + */ + double StaticVolume() + { + return mStaticVolume; + } + + /** + * Set Static Volume ... + * + * @param value: double + */ + void StaticVolume(double value) + { + // + value = NormalizeDouble(value, 0.01, 1); + + // + mStaticVolume = value; + } + + /** + * Get Dynamic Volume Step Balance ... + * used to Calculate Final Lottage ... + * + * @return ( double ) + */ + double DynamicVolumeStepBalance() + { + return mDynamicVolumeStepBalance; + } + + /** + * Set Dynamic Volume Step Balance ... + * used to Calculate Final Lottage ... + * + * @param value: Argument 1 + */ + void DynamicVolumeStepBalance(double value) + { + // + value = NormalizeDouble(value, 0); + + // + mDynamicVolumeStepBalance = value; + } + + /** + * Get Dynamic Volume Step Volume ... + * used to Calculate Final Lottage ... + * how much increase Final Volume based oBalance Step ... + * + * @return ( double ) + */ + double DynamicVolumeStepVolume() + { + return mDynamicVolumeStepVolume; + } + + /** + * Get Dynamic Volume Step Volume ... + * used to Calculate Final Lottage ... + * how much increase Final Volume based oBalance Step ... + * + * @param value: double + */ + void DynamicVolumeStepVolume(double value) + { + // + value = NormalizeDouble(value, 0.01, 0.1); + + // + mDynamicVolumeStepVolume = value; + } + + /** + * Get Constant Balance Use for Dyamic Volume Calculation ... + * + * @return ( double ) + */ + double ConstantBalance() + { + return mConstantBalance; + } + + /** + * Set Constant Balance Use for Dyamic Volume Calculation ... + * + * @param value: Argument 1 + */ + void ConstantBalance(double value) + { + // + value = NormalizeDouble(value, 0); + + // + mConstantBalance = value; + } + + /** + * Get Constant Risk Value Based on Account Currency ... + * + * @return ( double ) + */ + double ConstantRiskBalance() + { + return mConstantRiskBalance; + } + + /** + * Get Constant Risk Value Based on Account Currency ... + * + * @param value: double + */ + void ConstantRiskBalance(double value) + { + // + value = NormalizeDouble(value, 0); + + // + mConstantRiskBalance = value; + } + + /** + * Get Constant Percent Based On Selected Balance ... + * + * @return ( double ) + */ + double ConstantPercent() + { + return mConstantPercent; + } + + /** + * Set Constant Percent Based On Selected Balance ... + * + * @param value: double ... + */ + void ConstantPercent(double value) + { + // + value = NormalizeDouble(value, 0, 100); + + // + mConstantPercent = value; + } + + // + // Tools ... + + /** + * Retrieve Balance based on Provided Volume Type ... + * + * @return ( double ) + */ + double GetBalance() + { + // + double result = 0; + + // + if (!IsValid(mVolumeType)) + { + return result; + } + + // + if (mConstantBalance > 0 && + mVolumeType == X_VOLUME_CONSTANT) + { + result = mConstantBalance; + } + else if (mVolumeType == X_VOLUME_CURRENT) + { + result = account.GetBalance(); + } + else if (mVolumeType == X_VOLUME_EQUITY) + { + result = account.GetEquity(); + } + + // + return result; + } + + /** + * Retrieve Balance based on Provided Volume Type ... + * + * @return ( double ) + */ + double GetBalance(ENUM_X_VOLUME_SELECT_TYPE type) + { + // + double result = 0; + + // + if (!IsValid(type)) + { + return result; + } + + // + if (mConstantBalance > 0 && + type == X_VOLUME_CONSTANT) + { + result = mConstantBalance; + } + else if (type == X_VOLUME_CURRENT) + { + result = account.GetBalance(); + } + else if (type == X_VOLUME_EQUITY) + { + result = account.GetEquity(); + } + + // + return result; + } + + /** + * Calculate Volume Based On Given Configuration ... + * + * @param symbol: string, Trading Symbol ... + * @param entry: double, Entry Price ... + * @param sl: double, Stop Loss Price ... + * + * @return ( double ) + */ + double CalculateVolume( + string symbol, + double entry, + double sl // + ) + { + // + double result = X_MIN_VOLUME; + + // + bool has = false; + + // + // Validate Args ... + has = + sl > 0 && + entry > 0 && + IsValid(symbol); + if (!has) + { + return result; + } + + // + // Retrieve Balance Type ... + double balance = GetBalance(); + double points = GetPoints(symbol); + double riskPrice = MathAbs(entry - sl); + double riskInPoints = riskPrice / points; + + // + has = CanUseStaticVolume(); + if (has) + { + result = mStaticVolume; + } + + // + has = CanUseDynamicVolume(); + if (has) + { + // + double multiplier = balance / mDynamicVolumeStepBalance; + if (multiplier < 0) + { + multiplier = 1; + } + + // + result = multiplier * mDynamicVolumeStepVolume; + } + + // + has = CanUseConstantRiskBalance(); + if (has) + { + // + result = account.CalculateVolume( + symbol, + mConstantRiskBalance, + riskInPoints // + ); + } + + // + has = CanUseConstantBalancePercent(); + if (has) + { + // + double riskAmountPerBalance = (mConstantPercent * balance) / 100; + + // + result = account.CalculateVolume( + symbol, + riskAmountPerBalance, + riskInPoints // + ); + } + + // + if (result < X_MIN_VOLUME) + { + result = X_MIN_VOLUME; + } + + // + // Normalize Volume ... + result = NormalizeVolume(result, symbol); + + // + return result; + } + + /** + * Calculate Volume Based On Given Configuration ... + * + * @param signal: XSignal instance reference, provided required Data ... + * + * @return ( double ) + */ + double CalculateVolume(XSignal &signal) + { + // + double result = X_MIN_VOLUME; + + // + if (!signal.IsValid()) + { + return result; + } + + // + result = CalculateVolume( + signal.symbol, + signal.entry, + signal.sl // + ); + + // + return result; + } + + /** + * Calculate Specified Percent of Selected Balance for Volume ... + * + * @param percent: double, percent of Balance Risking ... + * @param symbol: string, Trading Symbol ... + * @param entry: double, Entry Price ... + * @param sl: double Stop Loss Price ... + * + * @return ( double ) + */ + double CalculateVolume( + ENUM_X_VOLUME_SELECT_TYPE selectType, + double percent, + string symbol, + double entry, + double sl // + ) + { + // + double result = X_MIN_VOLUME; + + // + bool has = false; + + // + // Validate Args ... + has = + sl > 0 && + entry > 0 && + percent > 0 && + IsValid(symbol) && + IsValid(selectType) && + (selectType == X_VOLUME_EQUITY || + selectType == X_VOLUME_CURRENT); + if (!has) + { + return result; + } + + // + // Retrieve Balance Type ... + double points = GetPoints(symbol); + double riskPrice = MathAbs(entry - sl); + double balance = GetBalance(selectType); + double riskInPoints = riskPrice / points; + + // + double riskAmountPerBalance = (percent * balance) / 100; + + // + result = account.CalculateVolume( + symbol, + riskAmountPerBalance, + riskInPoints // + ); + + // + return result; + } + + // + // Protected ... + protected: + // + // Tools ... + + /** + * Set Default Props ... + */ + void Default() + { + // + VolumeType(X_VOLUME_STATIC); + StaticVolume(0.01); + + // + ConstantBalance(0); + ConstantPercent(0); + ConstantRiskBalance(0); + + // + DynamicVolumeStepBalance(0); + DynamicVolumeStepVolume(0.01); + } + + /** + * Check Configuration is Valid For Static Volume ... + * + * @return ( bool ) + */ + bool CanUseStaticVolume() + { + // + bool result = false; + + // + result = IsValid(mVolumeType); + if (!result) + { + return result; + } + + // + // Static Volume ... + result = + // + mVolumeType == X_VOLUME_STATIC && + mStaticVolume > 0 && + // + mDynamicVolumeStepBalance == 0 && + // + mConstantBalance == 0 && + mConstantPercent == 0 && + mConstantRiskBalance == 0 + // + ; + + // + return result; + } + + /** + * Check Configuration is Valid For Dynamic Volume ... + * + * @return ( bool ) + */ + bool CanUseDynamicVolume() + { + // + bool result = false; + + // + result = IsValid(mVolumeType); + if (!result) + { + return result; + } + + // + result = + // + (mVolumeType == X_VOLUME_CURRENT || + mVolumeType == X_VOLUME_EQUITY || + (mVolumeType == X_VOLUME_CONSTANT && + mConstantBalance > 0)) && + // + mDynamicVolumeStepBalance > 0 && + mDynamicVolumeStepVolume > 0 && + // + mStaticVolume == 0 && + mConstantPercent == 0 && + mConstantRiskBalance == 0 + // + ; + + // + return result; + } + + /** + * Check Configuration is Valid For Constant Risk Balance ... + * + * @return ( bool ) + */ + bool CanUseConstantRiskBalance() + { + // + bool result = false; + + // + result = IsValid(mVolumeType); + if (!result) + { + return result; + } + + // + result = + // + (mVolumeType == X_VOLUME_CURRENT || + mVolumeType == X_VOLUME_EQUITY || + (mVolumeType == X_VOLUME_CONSTANT && + mConstantBalance > 0)) && + // + mConstantRiskBalance > 0 && + // + mStaticVolume == 0 && + mConstantPercent == 0 && + mDynamicVolumeStepBalance == 0 + // + ; + + // + return result; + } + + /** + * Check Configuration is Valid For Constant Risk Percent ... + * + * @return ( bool ) + */ + bool CanUseConstantBalancePercent() + { + // + bool result = false; + + // + result = IsValid(mVolumeType); + if (!result) + { + return result; + } + + // + result = + // + (mVolumeType == X_VOLUME_CURRENT || + mVolumeType == X_VOLUME_EQUITY || + (mVolumeType == X_VOLUME_CONSTANT && + mConstantBalance > 0)) && + // + mConstantPercent > 0 && + // + mStaticVolume == 0 && + mConstantRiskBalance == 0 && + mDynamicVolumeStepBalance == 0 + // + ; + + // + return result; + } + + // + // Private ... + private: + // + // Props ... + + // + ENUM_X_VOLUME_SELECT_TYPE mVolumeType; // Balance Type ... + + // + // Static Volume ... + double mStaticVolume; // Static Volume ... + + // + double mDynamicVolumeStepBalance; // Step of Balance ... + double mDynamicVolumeStepVolume; // Step of Volume ... + + // + double mConstantBalance; // Constant Balance .... + double mConstantRiskBalance; // Constant Risk Balance ... + double mConstantPercent; // Constant Percent of Balance ... +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Documents\Helpers\x-saherelm.x121.xcc.helper.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121XCCHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Input Models ... +struct X121XCCInputs +{ + // + // Props ... + + // + // Chart Style ... + ENUM_CHART_MODE mode; // Mode + color upColor; // Up Color + color downColor; // Down Color + color lineColor; // Line mode and Doji candlestick Color + color bearishColor; // Bullish Color + color bullishColor; // Bearish Color + color volumesColor; // Volumes Color + + // + // Presentation ... + bool showCandles; // Show Candles + + // + // Constructor(s) ... + X121XCCInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + mode = CHART_CANDLES; + + // + upColor = CLR_NONE; + downColor = CLR_NONE; + lineColor = CLR_NONE; + bearishColor = CLR_NONE; + bullishColor = CLR_NONE; + volumesColor = CLR_NONE; + + // + showCandles = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + mode = CHART_CANDLES; + + // + upColor = clrLime; + downColor = clrRed; + lineColor = clrLime; + bearishColor = clrRed; + bullishColor = clrLime; + volumesColor = clrGreen; + // + showCandles = true; + } + + // + // Hide all Visible Buffers ... + void Hide() + { + showCandles = false; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(0, 0); + + // + return result; + } +}; + +// +// Class ... +class XCX121XCCHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XCCHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XCCHelper() + { + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XCCInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xcc", + // + // Inputs ... + // + // Chart Style ... + "", + mInputs.mode, // Mode + mInputs.upColor, // Up Color + mInputs.downColor, // Down Color + mInputs.lineColor, // Line mode and Doji candlestick Color + mInputs.bullishColor, // Bearish Color + mInputs.bearishColor, // Bullish Color + mInputs.volumesColor, // Volumes Color + // + // Presentation ... + "", + mInputs.showCandles // Show Candles + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XCCInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XCCInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XCCInputs mInputs; // Inputs ... +}; + +// +// Tools ... + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Documents\Helpers\x-saherelm.x121.xct.helper.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121XCTHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Input Models ... +struct X121XCTInputs +{ + // + // Props ... + + // + string font; // Font + int fontSize; // Font Size; + color clr; // Text Color + ENUM_BASE_CORNER corner; // Text Position + + // + // Presentation ... + bool showCandleTime; // Show Candle Time + + // + // Constructor(s) ... + X121XCTInputs() + { + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + font = NULL; + fontSize = 15; + clr = CLR_NONE; + corner = CORNER_RIGHT_LOWER; + + // + // Presentation ... + showCandleTime = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + font = "Arial"; + fontSize = 15; + clr = clrYellow; + corner = CORNER_RIGHT_LOWER; + + // + // Presentation ... + showCandleTime = true; + } + + // + // Hide all Visible Buffers ... + void Hide() + { + showCandleTime = false; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(0, 0); + + // + return result; + } +}; + +// +// Class ... +class XCX121XCTHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XCTHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XCTHelper() + { + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XCTInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xct", + // + // Inputs ... + mInputs.fontSize, // Font Size ... + mInputs.font, // Font ... + mInputs.clr, // Text Color ... + mInputs.corner, // Text Position ... + // + // Presentation ... + "", + mInputs.showCandleTime // Show Candle Time + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XCTInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XCTInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XCTInputs mInputs; // Inputs ... +}; + +// +// Tools ... + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Documents\Indicators\x-saherelm.x121.xcc.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Candle Styles +// --------------------------------------------------- +// Name: X121 XCC +// Description: Candle Styles ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XCC Indicator" +#property strict + +// +// START Constants ... +// + +// +// Indicator Short Name ... +#define ShortName "X121 XCC" + +// +// Holds an SnapShot of Charts Configuration ... +struct XChartStyle +{ + // + // chart's ID ... + long chartId; + // + // chart's mode ... + ENUM_CHART_MODE mode; + // + // show bid line ... + bool showBidLine; + // + // show ask line ... + bool showAskLine; + // + // show grids on chart ... + bool showGrid; + // + // show volumes ... + bool showVolumes; + // + // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) ... + bool showTradeLevels; + // + // chart autoscroll ... + bool autoScroll; + // + // chart quick navigation state ... + bool quickNavigation; + // + // chart's foreground color ... + color foreGroundColor; + // + // chart's background color ... + color backGroundColor; + // + // Up Color ... + color upColor; + // + // Down Color ... + color downColor; + // + // Bullish color ... + color bullishColor; + // + // Bearish color ... + color bearishColor; + // + // grid color ... + color gridColor; + // + // bid line color ... + color bidLineColor; + // + // ask line color ... + color askLineColor; + // + // line mode and doji candlestick color ... + color lineColor; + // + // Color of stop order levels (Stop Loss and Take Profit) ... + color stopColor; + // + // volumes color ... + color volumesColor; +}; + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input group "Chart Style"; +input ENUM_CHART_MODE mode = CHART_CANDLES; // Mode +input color upColor = clrGreen; // Up Color +input color downColor = clrRed; // Down Color +input color lineColor = clrGreen; // Line mode and Doji candlestick Color +input color bullishColor = clrGreen; // Bullish Color +input color bearishColor = clrRed; // Bearish Color +input color volumesColor = clrGreen; // Volumes Color + +// +input group "Presentation"; +input bool showCandles = true; // Show Candles + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Draw Library ... +#include "../Libraries/x-saherelm.draw.lib.mq5" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 0 +#property indicator_plots 0 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +XChartStyle chartStyle; +XChartStyle clearStyle; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + drawPrefix = ShortName; + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Apply Chart Style ... + ApplyCustomChartStyle(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +// +// Calculating what we want ... +int OnCalculate( + const int rates_total, // Total Bars on Chart ... + const int prev_calculated, // Total Calculated Bars on Charts ... + const datetime &time[], // History of Open Time ... + const double &open[], // History of Open Price ... + const double &high[], // History of High Price ... + const double &low[], // History of Low Price ... + const double &close[], // History of Close Price ... + const long &tick_volume[], // History of Tick Volumes on Bar ... + const long &volume[], // History of Trade Volumes ... + const int &spread[] // History of Spread Price ... +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // this counts Available Bars ... + int limit; + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + CalculateBuffers(i); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = true; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index // Selected Bar Index +) +{ +} + +// +// Apply Custom Chart Style ... +void ApplyCustomChartStyle() +{ + // + // Read Current Chart Config and Store it ... + ReadChartStyle(); + + // + // After Reading Current Chart Style ... + // we have to Save Configs and Change Styles ... + clearStyle = chartStyle; + + // + clearStyle.upColor = CLR_NONE; + clearStyle.downColor = CLR_NONE; + clearStyle.lineColor = CLR_NONE; + clearStyle.bullishColor = CLR_NONE; + clearStyle.bearishColor = CLR_NONE; + + // + // Decide to Show or not Candles based on User Input ... + if (showCandles) + { + SetChartStyle(chartStyle); + } + else + { + SetChartStyle(clearStyle); + } +} + +// +// Read Previous Chart Style ... +void ReadChartStyle() +{ + // + // Retrieve Current Chart ID ... + long chartId = ChartID(); + chartStyle.chartId = chartId; + + // + // Retrieve Chart Mode ... + chartStyle.mode = (ENUM_CHART_MODE)ChartGetInteger(chartId, CHART_MODE); + + // + chartStyle.showBidLine = (bool)ChartGetInteger(chartId, CHART_SHOW_BID_LINE); + chartStyle.showAskLine = (bool)ChartGetInteger(chartId, CHART_SHOW_ASK_LINE); + chartStyle.showGrid = (bool)ChartGetInteger(chartId, CHART_SHOW_GRID); + chartStyle.showVolumes = (bool)ChartGetInteger(chartId, CHART_SHOW_VOLUMES); + chartStyle.showTradeLevels = (bool)ChartGetInteger(chartId, CHART_SHOW_TRADE_LEVELS); + chartStyle.autoScroll = (bool)ChartGetInteger(chartId, CHART_AUTOSCROLL); + chartStyle.quickNavigation = (bool)ChartGetInteger(chartId, CHART_QUICK_NAVIGATION); + + // + chartStyle.foreGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_FOREGROUND); + chartStyle.backGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_BACKGROUND); + chartStyle.upColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_UP); + chartStyle.downColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_DOWN); + chartStyle.bullishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BULL); + chartStyle.bearishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BEAR); + chartStyle.gridColor = (color)ChartGetInteger(chartId, CHART_COLOR_GRID); + chartStyle.bidLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_BID); + chartStyle.askLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_ASK); + chartStyle.stopColor = (color)ChartGetInteger(chartId, CHART_COLOR_STOP_LEVEL); + chartStyle.lineColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_LINE); + chartStyle.volumesColor = (color)ChartGetInteger(chartId, CHART_COLOR_VOLUME); + + // + chartStyle.mode = mode; + chartStyle.upColor = upColor; + chartStyle.downColor = downColor; + chartStyle.lineColor = lineColor; + chartStyle.bearishColor = bearishColor; + chartStyle.bullishColor = bullishColor; + chartStyle.volumesColor = volumesColor; +} + +// +// Set Chart Style ... +void SetChartStyle( + XChartStyle &mChartStyle // Chart Style to Apply +) +{ + // + ApplyChartStyle( + mChartStyle.chartId, + mChartStyle.mode, + mChartStyle.showBidLine, + mChartStyle.showAskLine, + mChartStyle.showGrid, + mChartStyle.showVolumes, + mChartStyle.showTradeLevels, + mChartStyle.autoScroll, + mChartStyle.quickNavigation, + mChartStyle.foreGroundColor, + mChartStyle.backGroundColor, + mChartStyle.upColor, + mChartStyle.downColor, + mChartStyle.bullishColor, + mChartStyle.bearishColor, + mChartStyle.gridColor, + mChartStyle.bidLineColor, + mChartStyle.askLineColor, + mChartStyle.lineColor, + mChartStyle.stopColor, + mChartStyle.volumesColor); +} + +// +// END Functions ... +// + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Documents\Indicators\x-saherelm.x121.xct.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121 XCT +// Description: Trend Magic Indicator ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XCT Indicator" +#property strict + +// +// START Constants ... +// + +// +#define ShortName "X121 XCT" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input int fontSize = 15; // Font Size +input string font = "Arial"; // Font +input color clr = clrYellow; // Text Color +input ENUM_BASE_CORNER corner = CORNER_RIGHT_LOWER; // Text Position + +// +input group "Presentation"; +input bool showTimer = true; // Show Candle Time + +// +// END Inputs ... +// + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 0 +#property indicator_plots 0 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// +bool isCreatedObject; +string tag; +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + + // + tag = ShortName + _Symbol + ToString(_Period); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Delete Object ... + ObjectDelete(0, tag); + + // + Comment(""); +} + +// +// Calculating what we want ... +int OnCalculate( + const int rates_total, // Total Bars on Chart ... + const int prev_calculated, // Total Calculated Bars on Charts ... + const datetime &time[], // History of Open Time ... + const double &open[], // History of Open Price ... + const double &high[], // History of High Price ... + const double &low[], // History of Low Price ... + const double &close[], // History of Close Price ... + const long &tick_volume[], // History of Tick Volumes on Bar ... + const long &volume[], // History of Trade Volumes ... + const int &spread[] // History of Spread Price ... +) +{ + // + if (!showTimer) + { + return rates_total; + } + + // + XBarRemainsTime barRemains; + barRemains.Init( + _Symbol, + _Period + // + ); + + // + string msg = barRemains + .ToString( + "", + "", + "", + "", + "", + ":", + true + // + ); + + // + long mSpread = SymbolInfoInteger(Symbol(), SYMBOL_SPREAD); + + // + string _sp = ""; + if (mSpread < 10) + _sp = ".."; + else if (mSpread < 100) + _sp = "."; + + // + string objText = "Spread: " + IntegerToString(mSpread) + _sp + ", Next Bar in: " + msg; + + // + if (IsValid(tag) && !isCreatedObject) + { + CreateIndicatorObject(); + } + + // + if (isCreatedObject) + { + ObjectSetString(0, tag, OBJPROP_TEXT, objText); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +void CreateIndicatorObject() +{ + // + if (!showTimer || + !IsValid(tag)) + { + return; + } + + // + isCreatedObject = ObjectCreate(0, tag, OBJ_LABEL, 0, 0, 0); + ObjectSetInteger(0, tag, OBJPROP_CORNER, corner); + ObjectSetInteger(0, tag, OBJPROP_XDISTANCE, 10); + ObjectSetInteger(0, tag, OBJPROP_YDISTANCE, 2); + + // + ENUM_ANCHOR_POINT Anchor = ANCHOR_LEFT_UPPER; + switch (corner) + { + case CORNER_LEFT_UPPER: + Anchor = ANCHOR_LEFT_UPPER; + break; + case CORNER_RIGHT_UPPER: + Anchor = ANCHOR_RIGHT_UPPER; + break; + case CORNER_LEFT_LOWER: + Anchor = ANCHOR_LEFT_LOWER; + break; + case CORNER_RIGHT_LOWER: + Anchor = ANCHOR_RIGHT_LOWER; + break; + } + + // + int mFontSize = fontSize > 0 + ? fontSize + : 10; + + // + string mFont = IsValid(font) + ? font + : "Arial"; + + // + ObjectSetString(0, tag, OBJPROP_FONT, mFont); + ObjectSetInteger(0, tag, OBJPROP_COLOR, clr); + ObjectSetInteger(0, tag, OBJPROP_ANCHOR, Anchor); + ObjectSetInteger(0, tag, OBJPROP_FONTSIZE, mFontSize); +} + +// +// END Functions ... +// + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Experts\x-saherelm.backtester.ea.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center XTest MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XBackTester +// Description: a Backtest Tools Strategy Tester +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +//////////////////////////////////////////////////////x +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property icon "../Images/SaherElm_Logo_Color.ico" +#property description "SaherElm XBackTester" +#property strict + +// +#define ShortName "XBackTester" + +// +// Imports ... +#include "../Classes/x-saherelm.x-backtester.expert.class.mq5" + +// +// Definitions ... + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 78692110; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Alert ... +// Here we Provider All Requirements for +// Configuring Alert Provider ... +input group "Alert"; +input bool eaEnableAlerts = true; // Enable Alerts +input bool eaLogAlerts = true; // Log Alerts +input bool eaMailAlerts = false; // Mail Alerts +input bool eaPushAlerts = false; // Push Alerts +input bool eaTerminalAlerts = false; // Terminal Alerts + +// +// Define Local Variables ... + +// +string eaLogTag; // EA Log Prefix ... +XCBackTesterEA *eaExpert; // EA Expert ... + +// +// Event Handlers ... + +// +// Initialization ... +int OnInit() +{ + // + // Preparing Tags ... + string eaTag = + (IsValid(eaLogSuffix) + ? eaLogSuffix + "_" + : "") + + ShortName; + + // + // Validate Inputs and Required Parameters + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) + { + return INIT_FAILED; + } + + // + // Configure EA Expert Class ... + eaExpert = new XCBackTesterEA(); + + // + // Symbol / Period ... + eaExpert.symbol = _Symbol; + eaExpert.period = _Period; + + // + // Common ... + eaExpert.eaMagicNumber = eaMagicNumber; + eaExpert.eaSlippage = eaSlippage; + eaExpert.eaLogSuffix = eaTag; + + // + // Alert ... + eaExpert.eaEnableAlerts = eaEnableAlerts; + eaExpert.eaLogAlerts = eaLogAlerts; + eaExpert.eaMailAlerts = eaMailAlerts; + eaExpert.eaPushAlerts = eaPushAlerts; + eaExpert.eaTerminalAlerts = eaTerminalAlerts; + + // + // Attach Event Handlers ... + eaExpert.AddOnDealsChangedEventHandler(OnDealsChanged); + eaExpert.AddOnStopLossEventHandler(OnStopLossTriggered); + eaExpert.AddOnOrdersChangedEventHandler(OnOrdersChanged); + eaExpert.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaExpert.AddOnModifyPositionEventHandler(OnPositionModified); + eaExpert.AddOnPositionsChangedEventHandler(OnPositionsChanged); + eaExpert.AddOnTradeStateChangedEventHandler(OnTradeStateChanged); + eaExpert.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + eaExpert.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); + + // + // Configure Other Requirements ... + // eaExpert.volume = 0; + // eaExpert.riskInPoint = 0; + // eaExpert.allowedTPSLStep = 0; + // eaExpert.riskToRewardRatio = 0; + // eaExpert.minAllowedRiskInPoint = 0; + + // + // Try to Initialize eaExpert ... + bool isInited = eaExpert.HandleOnInit(); + if (!isInited) + { + // + Print(ShortName, ": Initialization Failed ..."); + return INIT_FAILED; + } + + // + Print(ShortName, ": Initialized Successfully ..."); + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Destroy Timer ... + eaExpert.HandleOnDeInit(); + + // + delete eaExpert; + ZeroMemory(eaExpert); +} + +// +// On Tick Handler ... +void OnTick() +{ + eaExpert.HandleOnTick(); +} + +// +// Handle On Trade Event ... +void OnTrade() +{ + eaExpert.HandleOnTrade(); +} + +// +// On Timer ... +void OnTimer() +{ + eaExpert.HandleOnTimer(); +} + +// +// Chart Event Handler ... +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + eaExpert.HandleOnChartEvent(id, lparam, dparam, sparam); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +// +// Trade Event Handlers ... + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + eaExpert.HandleOnStopLossTriggered(deal); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + eaExpert.HandleOnTakeProfitTriggered(deal); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: ULONG ... + * @param position: XPosition instance ... + * @param comment: String ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + eaExpert.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); +} + +/** + * Handle Deals Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnDealsChanged(int count) +{ + eaExpert.HandleOnDealsChanged(count); +} + +/** + * Handle Orders Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnOrdersChanged(int count) +{ + eaExpert.HandleOnOrdersChanged(count); +} + +/** + * Handle Positions Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnPositionsChanged(int count) +{ + eaExpert.HandleOnPositionsChanged(count); +} + +/** + * Handle Position Modified ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionModified( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionModified( + ticket, + profit, + comment // + ); +} + +/** + * Handle Position Partial Closed ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionPartialClosed( + ticket, + profit, + comment // + ); +} + +/** + * Handle Trade State Changed ... + * + * @param state: XOnTradeHandlerState instance ... + */ +void OnTradeStateChanged(const XOnTradeHandlerState &state) +{ + eaExpert.HandleOnTradeStateChanged(state); +} + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Experts\x-saherelm.x-expert.ea.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Expert Advisor +// ------------------------------------------------- +// Name: XBaseEA +// Description: Base Expert Advisor as Template ... +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property icon "../Images/SaherElm_Logo_Color.ico" +#property description "SaherElm Based Expert Advisor" +#property strict + +// +#define ShortName "XBaseEA" + +// +// Importts ... +#include "../Classes/x-saherelm.x-expert.class.mq5" + +// +// Inputs ... + +// +// Common ... +input group "Common"; +input long eaMagicNumber = 1694056; // Magic Number +input int eaSlippage = 10; // Slippgae +input string eaLogSuffix = ""; // Log Suffix + +// +// Symbols +// [ +// Name| +// Symbol| +// period| +// (ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00)| +// maxAllowedSpread| +// maxAllowedPosition| +// ( +// restrictionsPeriod, +// restrictionsMultiplier, +// maxAllowedTPs, +// maxAllowedSLs, +// maxAllowedTrades, +// closeAllOpenTradesAt +// ) +// ] +// +// +// [XNAME|XAUUSDb|M5|(ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00)|25.0|5|(XTRADE_RESTRICATION_DAILY,1,0,2,0)] +input string eaSymbolConfiguration = "[XNAME|XAUUSDb|M5|(ST_04:00_08:30),(TL_10:30_12:00),(NY_16:00_20:00)|25.0|5|(XTRADE_RESTRICATION_DAILY,3,0,2,0)]"; // Symbol Configurations + +// +// Management ... +input group "Management"; +input bool eaAllowGuards = false; // Allow Guards +input bool eaAllowTrade = true; // Allow Trade on Signals +input bool eaAllowLongs = true; // Allow Long Trades +input bool eaAllowShorts = true; // Allow Short Trades +input double eaMaxAllowedDrawdownFactor = 0.3; // Max Allowed DrawDown for Trade + +// +// Volume ... +input group "Volume"; +input ENUM_X_VOLUME_SELECT_TYPE eaVolumeSelect = X_VOLUME_CONSTANT; // Volume Applying Type +input double eaStaticVoluem = 0.0; // Static Volume +input double eaDynamicVolumeStepBalance = 0.0; // Step of Balance for Increase Volume +input double eaDynamicVolumeStepVolume = X_MIN_VOLUME; // Step of Volume Increasing +input double eaConstantRiskBalance = 0.0; // Constant Risk Balance per Trade +input double eaConstantPercent = 1; // Constant Percent of Balance Per Trade +input double eaConstantBalance = 1000.0; // Constant Balance for Calculations + +// +// Alert ... +input group "Alert"; +input bool eaEnableAlerts = true; // Enable Alerts +input bool eaSaveAlerts = true; // Save Alerts +input bool eaLogAlerts = true; // Log Alerts +input bool eaMailAlerts = false; // Mail Alerts +input bool eaPushAlerts = true; // Push Alerts +input bool eaTerminalAlerts = false; // Terminal Alerts + +// +// Reports ... +input group "Reports"; +input bool eaReportNewMonths = false; // Report New Month +input bool eaReportNewWeeks = false; // Report New Weeks +input bool eaReportNewDays = true; // Report New Days +input bool eaReportNewHours = false; // Report New Hours +input bool eaReportTrades = true; // Report Trades +input bool eaReportSignals = true; // Report Signals +input bool eaReportRestrictions = true; // Report Restrictions +input bool eaReportProtector = true; // Report Protector Actions +input bool eaReportAfterTradesBalance = true; // Report Balance after a Trade Finished + +// +// Collector ... +input group "Collector"; +input bool eaSaveTrades = true; // Save Trades +input bool eaSaveSignals = true; // Save Signals +input bool eaSaveWins = true; // Save Winning Conditions +input bool eaSaveLosts = true; // Save Lost Conditions +input bool eaSaveRestrictions = true; // Save Restriction Reports + +// +// Management Panel ... +input group "Management Panel"; +input bool eaShowPanel = false; // Show Management Panel +double eaPanelAllowedTPSLStep = 10; // Value for Change TP/SL in Each Step +double eaPanelMinAllowedRiskInPoint = 20; // Min Allowed Risk in Point +double eaPanelRiskInPoint = 50; // Risk in Point per Trades +double eaPanelRiskToRewardRatio = 2.0; // Risk To Reward per Trades +double eaPanelVolume = X_MIN_VOLUME; // Default volume Per Trade + +// +// Variables ... + +// +XCBaseExpert *eaExpert; + +// +// Event Handlers ... + +/** + * Initialize EA Process ... + * + * @return ( int ) + */ +int OnInit() +{ + // + // Preparing Tags ... + string eaTag = + (IsValid(eaLogSuffix) + ? eaLogSuffix + "_" + : "") + + ShortName; + + // + // Validate Inputs and Required Parameters ... + + // for EA to Works fine ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + // Initialize Timer ... + if (!InitTimer()) + { + return INIT_FAILED; + } + + // + // Configure EA Expert Class ... + eaExpert = new XCBaseExpert(); + + // + // Setting All Inputs to Expert Adviser Class ... + + // + // Common ... + eaExpert.eaMagicNumber = eaMagicNumber; + eaExpert.eaSlippage = eaSlippage; + eaExpert.eaLogSuffix = eaTag; + + // + // Symbols ... + eaExpert.eaSymbolConfiguration = eaSymbolConfiguration; + + // + // Management ... + eaExpert.eaAllowGuards = eaAllowGuards; + eaExpert.eaAllowTrade = eaAllowTrade; + eaExpert.eaAllowLongs = eaAllowLongs; + eaExpert.eaAllowShorts = eaAllowShorts; + eaExpert.eaMaxAllowedDrawdownFactor = eaMaxAllowedDrawdownFactor; + + // + // Volume ... + eaExpert.eaVolumeSelect = eaVolumeSelect; + eaExpert.eaStaticVoluem = eaStaticVoluem; + eaExpert.eaDynamicVolumeStepBalance = eaDynamicVolumeStepBalance; + eaExpert.eaDynamicVolumeStepVolume = eaDynamicVolumeStepVolume; + eaExpert.eaConstantRiskBalance = eaConstantRiskBalance; + eaExpert.eaConstantPercent = eaConstantPercent; + eaExpert.eaConstantBalance = eaConstantBalance; + + // + // Alert ... + eaExpert.eaEnableAlerts = eaEnableAlerts; + eaExpert.eaSaveAlerts = eaSaveAlerts; + eaExpert.eaLogAlerts = eaLogAlerts; + eaExpert.eaMailAlerts = eaMailAlerts; + eaExpert.eaPushAlerts = eaPushAlerts; + eaExpert.eaTerminalAlerts = eaTerminalAlerts; + + // + // Reports ... + eaExpert.eaReportNewMonths = eaReportNewMonths; + eaExpert.eaReportNewWeeks = eaReportNewWeeks; + eaExpert.eaReportNewDays = eaReportNewDays; + eaExpert.eaReportNewHours = eaReportNewHours; + eaExpert.eaReportTrades = eaReportTrades; + eaExpert.eaReportSignals = eaReportSignals; + eaExpert.eaReportRestrictions = eaReportRestrictions; + eaExpert.eaReportProtector = eaReportProtector; + eaExpert.eaReportAfterTradesBalance = eaReportAfterTradesBalance; + + // + // Collector ... + eaExpert.eaSaveTrades = eaSaveTrades; + eaExpert.eaSaveSignals = eaSaveSignals; + eaExpert.eaSaveWins = eaSaveWins; + eaExpert.eaSaveLosts = eaSaveLosts; + eaExpert.eaSaveRestrictions = eaSaveRestrictions; + + // + // Management Panel ... + eaExpert.eaShowPanel = eaShowPanel; + eaExpert.eaPanelAllowedTPSLStep = eaPanelAllowedTPSLStep; + eaExpert.eaPanelMinAllowedRiskInPoint = eaPanelMinAllowedRiskInPoint; + eaExpert.eaPanelRiskInPoint = eaPanelRiskInPoint; + eaExpert.eaPanelRiskToRewardRatio = eaPanelRiskToRewardRatio; + eaExpert.eaPanelVolume = eaPanelVolume; + + // + // Attach Event Handlers ... + eaExpert.AddOnSignalEventHandler(OnSignalTriggered); + eaExpert.onGuardedEventHandler = OnGuardedTriggered; + eaExpert.AddOnDealsChangedEventHandler(OnDealsChanged); + eaExpert.AddOnStopLossEventHandler(OnStopLossTriggered); + eaExpert.AddOnOrdersChangedEventHandler(OnOrdersChanged); + eaExpert.AddOnSignalExecutedEventHandler(OnSignalExecuted); + eaExpert.canAnalyseEventHandler = CanAnalyseEventTriggered; + eaExpert.AddOnTakeProfitEventHandler(OnTakeProfitTriggered); + eaExpert.checkForGuardEventHandler = CheckForGuardTriggered; + eaExpert.AddOnModifyPositionEventHandler(OnPositionModified); + eaExpert.AddOnPositionsChangedEventHandler(OnPositionsChanged); + eaExpert.AddOnTradeStateChangedEventHandler(OnTradeStateChanged); + eaExpert.AddOnForceClosePositionEventHandler(OnPositionForceClosed); + eaExpert.AddOnPartialClosePositionEventHandler(OnPositionPartialClosed); + + // + // Try to Initialize eaExpert ... + bool isInited = eaExpert.HandleOnInit(); + if (!isInited) + { + // + Print(ShortName, ": Initialization Failed ..."); + return INIT_FAILED; + } + + // + Print(ShortName, ": Initialized Successfully ..."); + return INIT_SUCCEEDED; +} + +/** + * De Initialize Expert ... + * + * @param reason: int, DeInitialization Reason ... + * + * REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + * REASON_REMOVE 1 Program removed from a chart + * REASON_RECOMPILE 2 Program recompiled + * REASON_CHARTCHANGE 3 A symbol or a chart period is changed + * REASON_CHARTCLOSE 4 Chart closed + * REASON_PARAMETERS 5 Inputs changed by a user + * REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + * REASON_TEMPLATE 7 Another chart template applied + * REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + * REASON_CLOSE 9 Terminal closed + * + */ +void OnDeinit(const int reason) +{ + // + // Destroy Timer ... + // If Initialized ... + + // + // De Init Expert Class Instance ... + eaExpert.HandleOnDeInit(); + + // + // Cleanup Resources ... + delete eaExpert; + ZeroMemory(eaExpert); +} + +/** + * Handle Tick for Processing ... + */ +void OnTick() +{ + eaExpert.HandleOnTick(); +} + +/** + * Handle On Trade Processing ... + */ +void OnTrade() +{ + eaExpert.HandleOnTrade(); +} + +/** + * Handle On Timer Processing ... + */ +void OnTimer() +{ + eaExpert.HandleOnTimer(); +} + +/** + * Handle On Chart Event Processing ... + + * @param id: int, Specified Event ID ... + * @param lparam: long, type event parameter + * @param dparam: double, type event parameter + * @param sparam: string, type event parameter + */ +void OnChartEvent( + const int id, + const long &lparam, + const double &dparam, + const string &sparam // +) +{ + eaExpert.HandleOnChartEvent(id, lparam, dparam, sparam); +} + +// +// Event Listeners ... + +/** + * Handle CanAnalyse Event Triggered ... + * + * @param symbol: Symbol ... + * @param period: Period ... + * @param time: Analysing Time ... + * + * @return ( bool ) + */ +bool CanAnalyseEventTriggered( + string symbol, + ENUM_TIMEFRAMES period, + datetime time // +) +{ + return eaExpert.HandleCanAnalyseEventTriggered( + symbol, + period, + time // + ); +} + +/** + * Check For Guard ... + * + * @param guards: XGuard, reference Collection to holds result ... + * @param positions: XPosition, refrence collection to Provides Positions ... + * @param barIndex: int, Specified Bar index ... + * + * @return ( int ) + */ +int CheckForGuardTriggered( + XGuard &guards[], + XPosition &positions[], + int barIndex = 0 // +) +{ + // + return eaExpert.CheckForGuardTriggered( + guards, + positions, + barIndex // + ); +} + +/** + * Handle Guard Events ... + * + * @param action: ENUM_X_GUARD_ACTIONS + * @param positions: XPosition[] + */ +void OnGuardedTriggered( + ENUM_X_GUARD_ACTIONS action, + XPosition &positions[] // +) +{ + eaExpert.OnGuardedTriggered(action, positions); +} + +/** + * Trigger OnSignal Event ... + * + * @param signal: XSignal + */ +void OnSignalTriggered(XSignal &signal) +{ + eaExpert.HandleOnSignalTriggered(signal); +} + +/** + * Trigger OnSignal Executed Event ... + * + * @param signal: XSignal + */ +void OnSignalExecuted(XSignal &signal) +{ + eaExpert.HandleOnSignalExecuted(signal); +} + +/** + * Handle StopLoss Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnStopLossTriggered(const XDeal &deal) +{ + eaExpert.HandleOnStopLossTriggered(deal); +} + +/** + * Handle Take Profit Triggered Positions ... + * + * @param deal: XDeal instance ... + */ +void OnTakeProfitTriggered(const XDeal &deal) +{ + eaExpert.HandleOnTakeProfitTriggered(deal); +} + +/** + * Handle Force Close a Position ... + * + * @param ticket: ULONG ... + * @param position: XPosition instance ... + * @param comment: String ... + */ +void OnPositionForceClosed( + const ulong ticket, + const XPosition &position, + const string comment // +) +{ + // + eaExpert.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); +} + +/** + * Handle Deals Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnDealsChanged(int count) +{ + eaExpert.HandleOnDealsChanged(count); +} + +/** + * Handle Orders Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnOrdersChanged(int count) +{ + eaExpert.HandleOnOrdersChanged(count); +} + +/** + * Handle Positions Changes ... + * + * @param count: Integer, Number of Changes ... + */ +void OnPositionsChanged(int count) +{ + eaExpert.HandleOnPositionsChanged(count); +} + +/** + * Handle Position Modified ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionModified( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionModified( + ticket, + profit, + comment // + ); +} + +/** + * Handle Position Partial Closed ... + * + * @param ticket: ulong, Position Ticket ... + * @param profit: double, Position Profit ... + * @param comment: string, Comment ... + */ +void OnPositionPartialClosed( + const ulong ticket, + const double profit, + const string comment // +) +{ + // + eaExpert.HandleOnPositionPartialClosed( + ticket, + profit, + comment // + ); +} + +/** + * Handle Trade State Changed ... + * + * @param state: XOnTradeHandlerState instance ... + */ +void OnTradeStateChanged(const XOnTradeHandlerState &state) +{ + eaExpert.HandleOnTradeStateChanged(state); +} + +// +// Custom Functions ... + +/** + * Validate all Inputs of Expert Adviser ... + * + * @return ( bool ) + */ +bool ValidateInputs() +{ + // + bool result = false; + + // + string errMessage = ""; + + // + bool isCommonValid = ( + // + eaSlippage > 0 && + eaMagicNumber > 0 + // + ); + if (!isCommonValid) + { + // + errMessage += "common configurations error;" + "\n"; + } + + // + result = + // + // Common ... + isCommonValid && + // + // Otere ... + true + // + ; + + // + if (!result) + { + // + // Since here Logger not Initiallized, we Use Raw Print Command ... + Print(ShortName + " Errors: \n", errMessage); + } + + // + return result; +} + +/** + * Initialize Timer ... + * + * @return ( bool ) + */ +bool InitTimer() +{ + // + bool result = false; + + // + // TODO: Initialize Timer if necessary ... + // result = EventSetTimer(1); + // result = EventSetMillisecondTimer(100); + result = true; + + // + return result; +} + +/** + * Destroy Timer ... + */ +void DestroyTimer() +{ + // + // TODO: Use This ... + // EventKillTimer(); +} + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Helpers\x-saherelm.x121.xcc.helper.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121XCCHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Input Models ... +struct X121XCCInputs +{ + // + // Props ... + + // + // Chart Style ... + ENUM_CHART_MODE mode; // Mode + color upColor; // Up Color + color downColor; // Down Color + color lineColor; // Line mode and Doji candlestick Color + color bearishColor; // Bullish Color + color bullishColor; // Bearish Color + color volumesColor; // Volumes Color + + // + // Presentation ... + bool showCandles; // Show Candles + + // + // Constructor(s) ... + X121XCCInputs() + { + // + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + mode = CHART_CANDLES; + + // + upColor = CLR_NONE; + downColor = CLR_NONE; + lineColor = CLR_NONE; + bearishColor = CLR_NONE; + bullishColor = CLR_NONE; + volumesColor = CLR_NONE; + + // + showCandles = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + mode = CHART_CANDLES; + + // + upColor = clrLime; + downColor = clrRed; + lineColor = clrLime; + bearishColor = clrRed; + bullishColor = clrLime; + volumesColor = clrGreen; + // + showCandles = true; + } + + // + // Hide all Visible Buffers ... + void Hide() + { + showCandles = false; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(0, 0); + + // + return result; + } +}; + +// +// Class ... +class XCX121XCCHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XCCHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XCCHelper() + { + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XCCInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xcc", + // + // Inputs ... + // + // Chart Style ... + "", + mInputs.mode, // Mode + mInputs.upColor, // Up Color + mInputs.downColor, // Down Color + mInputs.lineColor, // Line mode and Doji candlestick Color + mInputs.bullishColor, // Bearish Color + mInputs.bearishColor, // Bullish Color + mInputs.volumesColor, // Volumes Color + // + // Presentation ... + "", + mInputs.showCandles // Show Candles + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XCCInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XCCInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XCCInputs mInputs; // Inputs ... +}; + +// +// Tools ... + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Helpers\x-saherelm.x121.xct.helper.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Helper Class Library +// ---------------------------------------------- +// Name: XSCX121XCTHelper +// Description: provides all Indicator +// Helper requirements ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.x-helper.class.mq5" + +// +// Definitions ... + +// +// Input Models ... +struct X121XCTInputs +{ + // + // Props ... + + // + string font; // Font + int fontSize; // Font Size; + color clr; // Text Color + ENUM_BASE_CORNER corner; // Text Position + + // + // Presentation ... + bool showCandleTime; // Show Candle Time + + // + // Constructor(s) ... + X121XCTInputs() + { + Clean(); + } + + // + // Tools ... + + // + // Clean ... + void Clean() + { + // + font = NULL; + fontSize = 15; + clr = CLR_NONE; + corner = CORNER_RIGHT_LOWER; + + // + // Presentation ... + showCandleTime = false; + + // + ZeroMemory(this); + } + + // + // Default ... + void Default() + { + // + font = "Arial"; + fontSize = 15; + clr = clrYellow; + corner = CORNER_RIGHT_LOWER; + + // + // Presentation ... + showCandleTime = true; + } + + // + // Hide all Visible Buffers ... + void Hide() + { + showCandleTime = false; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + true + // + ; + + // + return result; + } + + // + // Retrieve MAx Length ... + int Max() + { + // + int result = 0; + + // + result = MathMax(0, 0); + + // + return result; + } +}; + +// +// Class ... +class XCX121XCTHelper : public XCBaseHelper +{ + // + // Public ... + public: + // + // Props ... + + // + // Constructors ... + XCX121XCTHelper() + : XCBaseHelper(_Symbol, _Period) + { + } + + // + // Deconstructor ... + ~XCX121XCTHelper() + { + mInputs.Clean(); + } + + // + // Tools ... + bool Init( + string symbol, // Trading Symbol + ENUM_TIMEFRAMES period, // Trading Period + X121XCTInputs &inputs // Inputs + ) + { + // + bool result = false; + + // + mSymbol = symbol; + mPeriod = period; + + // + result = inputs.IsValid(); + if (!result) + { + return result; + } + + // + mInputs = inputs; + + // + mHandler = iCustom( + mSymbol, + mPeriod, + "x-saherelm.x121.xct", + // + // Inputs ... + mInputs.fontSize, // Font Size ... + mInputs.font, // Font ... + mInputs.clr, // Text Color ... + mInputs.corner, // Text Position ... + // + // Presentation ... + "", + mInputs.showCandleTime // Show Candle Time + // + ); + result = mHandler != INVALID_HANDLE; + if (!result) + { + return result; + } + + // + return result; + } + + // + // Inputs ... + + // + X121XCTInputs GetInputs() + { + return mInputs; + } + + // + bool SetInputs( + X121XCTInputs &inputs // Configs + ) + { + // + return Init( + mSymbol, + mPeriod, + inputs + // + ); + } + + // + // Protected ... + protected: + // + // Private ... + private: + // + // Props ... + X121XCTInputs mInputs; // Inputs ... +}; + +// +// Tools ... + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Indicators\x-saherelm.x121.xcc.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Candle Styles +// --------------------------------------------------- +// Name: X121 XCC +// Description: Candle Styles ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XCC Indicator" +#property icon "../Images/SaherElm_Logo_Color.ico" +#property strict + +// +// START Constants ... +// + +// +// Indicator Short Name ... +#define ShortName "X121 XCC" + +// +// Holds an SnapShot of Charts Configuration ... +struct XChartStyle +{ + // + // chart's ID ... + long chartId; + // + // chart's mode ... + ENUM_CHART_MODE mode; + // + // show bid line ... + bool showBidLine; + // + // show ask line ... + bool showAskLine; + // + // show grids on chart ... + bool showGrid; + // + // show volumes ... + bool showVolumes; + // + // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) ... + bool showTradeLevels; + // + // chart autoscroll ... + bool autoScroll; + // + // chart quick navigation state ... + bool quickNavigation; + // + // chart's foreground color ... + color foreGroundColor; + // + // chart's background color ... + color backGroundColor; + // + // Up Color ... + color upColor; + // + // Down Color ... + color downColor; + // + // Bullish color ... + color bullishColor; + // + // Bearish color ... + color bearishColor; + // + // grid color ... + color gridColor; + // + // bid line color ... + color bidLineColor; + // + // ask line color ... + color askLineColor; + // + // line mode and doji candlestick color ... + color lineColor; + // + // Color of stop order levels (Stop Loss and Take Profit) ... + color stopColor; + // + // volumes color ... + color volumesColor; +}; + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input group "Chart Style"; +input ENUM_CHART_MODE mode = CHART_CANDLES; // Mode +input color upColor = clrGreen; // Up Color +input color downColor = clrRed; // Down Color +input color lineColor = clrGreen; // Line mode and Doji candlestick Color +input color bullishColor = clrGreen; // Bullish Color +input color bearishColor = clrRed; // Bearish Color +input color volumesColor = clrGreen; // Volumes Color + +// +input group "Presentation"; +input bool showCandles = true; // Show Candles + +// +// END Inputs ... +// + +// +// START Includes and Imports ... +// + +// +// Includes Draw Library ... +#include "../Libraries/x-saherelm.draw.lib.mq5" + +// +// Includes Common Library ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Includes and Imports ... +// + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 0 +#property indicator_plots 0 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// + +// +int maxLength; + +// +XChartStyle chartStyle; +XChartStyle clearStyle; + +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + if (!ValidateInputs()) + { + return INIT_PARAMETERS_INCORRECT; + } + + // + drawPrefix = ShortName; + + // + // because in some cases we may have more than one input for + // calculation and we must prevent any calculation + // untill we pass the biggest input length, here we get max Input length + // and then wait until pass it ... + maxLength = ExtractMaxLengthOfInputs(); + + // + // Define Index Buffers ... + DefineBuffers(); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Apply Chart Style ... + ApplyCustomChartStyle(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed +} + +// +// Calculating what we want ... +int OnCalculate( + const int rates_total, // Total Bars on Chart ... + const int prev_calculated, // Total Calculated Bars on Charts ... + const datetime &time[], // History of Open Time ... + const double &open[], // History of Open Price ... + const double &high[], // History of High Price ... + const double &low[], // History of Low Price ... + const double &close[], // History of Close Price ... + const long &tick_volume[], // History of Tick Volumes on Bar ... + const long &volume[], // History of Trade Volumes ... + const int &spread[] // History of Spread Price ... +) +{ + // + // Prepare Buffers ... + ArraySetAsSeries(time, true); + ArraySetAsSeries(open, true); + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(close, true); + ArraySetAsSeries(tick_volume, true); + ArraySetAsSeries(volume, true); + ArraySetAsSeries(spread, true); + + // + // this counts Available Bars ... + int limit; + + // + limit = (prev_calculated > rates_total || prev_calculated <= 0) ? rates_total : (rates_total - prev_calculated) + 1; + + // + // Main Loop ... + for (int i = limit - 1; i >= 0 && !IsStopped(); i--) + { + CalculateBuffers(i); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Validate Input Args for Initialization ... +bool ValidateInputs() +{ + // + bool result = true; + + // + return result; +} + +// +// Retrieve all Exists Input Max Length ... +// use for Start Of Drawing ... +int ExtractMaxLengthOfInputs() +{ + // + int result = 0; + + // + return result; +} + +// +// Define Indexes and Styles ... +void DefineBuffers() +{ +} + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +// Calculate Buffers ... +void CalculateBuffers( + int bar_index // Selected Bar Index +) +{ +} + +// +// Apply Custom Chart Style ... +void ApplyCustomChartStyle() +{ + // + // Read Current Chart Config and Store it ... + ReadChartStyle(); + + // + // After Reading Current Chart Style ... + // we have to Save Configs and Change Styles ... + clearStyle = chartStyle; + + // + clearStyle.upColor = CLR_NONE; + clearStyle.downColor = CLR_NONE; + clearStyle.lineColor = CLR_NONE; + clearStyle.bullishColor = CLR_NONE; + clearStyle.bearishColor = CLR_NONE; + + // + // Decide to Show or not Candles based on User Input ... + if (showCandles) + { + SetChartStyle(chartStyle); + } + else + { + SetChartStyle(clearStyle); + } +} + +// +// Read Previous Chart Style ... +void ReadChartStyle() +{ + // + // Retrieve Current Chart ID ... + long chartId = ChartID(); + chartStyle.chartId = chartId; + + // + // Retrieve Chart Mode ... + chartStyle.mode = (ENUM_CHART_MODE)ChartGetInteger(chartId, CHART_MODE); + + // + chartStyle.showBidLine = (bool)ChartGetInteger(chartId, CHART_SHOW_BID_LINE); + chartStyle.showAskLine = (bool)ChartGetInteger(chartId, CHART_SHOW_ASK_LINE); + chartStyle.showGrid = (bool)ChartGetInteger(chartId, CHART_SHOW_GRID); + chartStyle.showVolumes = (bool)ChartGetInteger(chartId, CHART_SHOW_VOLUMES); + chartStyle.showTradeLevels = (bool)ChartGetInteger(chartId, CHART_SHOW_TRADE_LEVELS); + chartStyle.autoScroll = (bool)ChartGetInteger(chartId, CHART_AUTOSCROLL); + chartStyle.quickNavigation = (bool)ChartGetInteger(chartId, CHART_QUICK_NAVIGATION); + + // + chartStyle.foreGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_FOREGROUND); + chartStyle.backGroundColor = (color)ChartGetInteger(chartId, CHART_COLOR_BACKGROUND); + chartStyle.upColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_UP); + chartStyle.downColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_DOWN); + chartStyle.bullishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BULL); + chartStyle.bearishColor = (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BEAR); + chartStyle.gridColor = (color)ChartGetInteger(chartId, CHART_COLOR_GRID); + chartStyle.bidLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_BID); + chartStyle.askLineColor = (color)ChartGetInteger(chartId, CHART_COLOR_ASK); + chartStyle.stopColor = (color)ChartGetInteger(chartId, CHART_COLOR_STOP_LEVEL); + chartStyle.lineColor = (color)ChartGetInteger(chartId, CHART_COLOR_CHART_LINE); + chartStyle.volumesColor = (color)ChartGetInteger(chartId, CHART_COLOR_VOLUME); + + // + chartStyle.mode = mode; + chartStyle.upColor = upColor; + chartStyle.downColor = downColor; + chartStyle.lineColor = lineColor; + chartStyle.bearishColor = bearishColor; + chartStyle.bullishColor = bullishColor; + chartStyle.volumesColor = volumesColor; +} + +// +// Set Chart Style ... +void SetChartStyle( + XChartStyle &mChartStyle // Chart Style to Apply +) +{ + // + ApplyChartStyle( + mChartStyle.chartId, + mChartStyle.mode, + mChartStyle.showBidLine, + mChartStyle.showAskLine, + mChartStyle.showGrid, + mChartStyle.showVolumes, + mChartStyle.showTradeLevels, + mChartStyle.autoScroll, + mChartStyle.quickNavigation, + mChartStyle.foreGroundColor, + mChartStyle.backGroundColor, + mChartStyle.upColor, + mChartStyle.downColor, + mChartStyle.bullishColor, + mChartStyle.bearishColor, + mChartStyle.gridColor, + mChartStyle.bidLineColor, + mChartStyle.askLineColor, + mChartStyle.lineColor, + mChartStyle.stopColor, + mChartStyle.volumesColor); +} + +// +// END Functions ... +// + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Indicators\x-saherelm.x121.xct.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Indicator +// --------------------------------------------- +// Name: X121 XCT +// Description: Trend Magic Indicator ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://saherelm.ir" +#property version "1.00" +#property description "SaherElm X121 XCT Indicator" +#property icon "../Images/SaherElm_Logo_Color.ico" +#property strict + +// +// START Constants ... +// + +// +#define ShortName "X121 XCT" +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// END Constants ... +// + +// +// START Inputs ... +// + +// +input int fontSize = 15; // Font Size +input string font = "Arial"; // Font +input color clr = clrYellow; // Text Color +input ENUM_BASE_CORNER corner = CORNER_RIGHT_LOWER; // Text Position + +// +input group "Presentation"; +input bool showTimer = true; // Show Candle Time + +// +// END Inputs ... +// + +// +// START Buffers ... +// + +// +#property indicator_chart_window + +// +#property indicator_buffers 0 +#property indicator_plots 0 + +// +// END Buffers ... +// + +// +// START Global Definitions: Variables, Properties and etc ... +// +bool isCreatedObject; +string tag; +// +// END Global Definitions: Variables, Properties and etc ... +// + +// +// START Event Handlers ... +// + +// +// Initialization ... +int OnInit() +{ + // + // Validate Inputs ... + + // + tag = ShortName + _Symbol + ToXString(_Period); + + // + // Set Indicator ShortName ... + SetIndicatorName(); + + // + // Init Succeed ... + return INIT_SUCCEEDED; +} + +// +// DeInitialization ... +void OnDeinit(const int reason) +{ + // + // REASON_PROGRAM 0 The EA has stopped working calling the ExpertRemove() function + // REASON_REMOVE 1 Program removed from a chart + // REASON_RECOMPILE 2 Program recompiled + // REASON_CHARTCHANGE 3 A symbol or a chart period is changed + // REASON_CHARTCLOSE 4 Chart closed + // REASON_PARAMETERS 5 Inputs changed by a user + // REASON_ACCOUNT 6 Another account has been activated or reconnection to the trade server has occurred due to changes in the account settings + // REASON_TEMPLATE 7 Another chart template applied + // REASON_INITFAILED 8 The OnInit() handler returned a non-zero value + // REASON_CLOSE 9 Terminal closed + + // + // Delete Object ... + ObjectDelete(0, tag); + + // + Comment(""); +} + +// +// Calculating what we want ... +int OnCalculate( + const int rates_total, // Total Bars on Chart ... + const int prev_calculated, // Total Calculated Bars on Charts ... + const datetime &time[], // History of Open Time ... + const double &open[], // History of Open Price ... + const double &high[], // History of High Price ... + const double &low[], // History of Low Price ... + const double &close[], // History of Close Price ... + const long &tick_volume[], // History of Tick Volumes on Bar ... + const long &volume[], // History of Trade Volumes ... + const int &spread[] // History of Spread Price ... +) +{ + // + if (!showTimer) + { + return rates_total; + } + + // + XBarRemainsTime barRemains; + barRemains.Init( + _Symbol, + _Period + // + ); + + // + string msg = barRemains + .ToString( + "", + "", + "", + "", + "", + ":", + true + // + ); + + // + long mSpread = SymbolInfoInteger(Symbol(), SYMBOL_SPREAD); + + // + string _sp = ""; + if (mSpread < 10) + _sp = ".."; + else if (mSpread < 100) + _sp = "."; + + // + string objText = "Spread: " + IntegerToString(mSpread) + _sp + ", Next Bar in: " + msg; + + // + if (IsValid(tag) && !isCreatedObject) + { + CreateIndicatorObject(); + } + + // + if (isCreatedObject) + { + ObjectSetString(0, tag, OBJPROP_TEXT, objText); + } + + // + return rates_total; +} + +// +// END Event Handlers ... +// + +// +// START Functions ... +// + +// +// Set Indicator Short Name and also we can define Buffers Labels ... +void SetIndicatorName() +{ + IndicatorSetString(INDICATOR_SHORTNAME, ShortName); +} + +// +void CreateIndicatorObject() +{ + // + if (!showTimer || + !IsValid(tag)) + { + return; + } + + // + isCreatedObject = ObjectCreate(0, tag, OBJ_LABEL, 0, 0, 0); + ObjectSetInteger(0, tag, OBJPROP_CORNER, corner); + ObjectSetInteger(0, tag, OBJPROP_XDISTANCE, 10); + ObjectSetInteger(0, tag, OBJPROP_YDISTANCE, 2); + + // + ENUM_ANCHOR_POINT Anchor = ANCHOR_LEFT_UPPER; + switch (corner) + { + case CORNER_LEFT_UPPER: + Anchor = ANCHOR_LEFT_UPPER; + break; + case CORNER_RIGHT_UPPER: + Anchor = ANCHOR_RIGHT_UPPER; + break; + case CORNER_LEFT_LOWER: + Anchor = ANCHOR_LEFT_LOWER; + break; + case CORNER_RIGHT_LOWER: + Anchor = ANCHOR_RIGHT_LOWER; + break; + } + + // + int mFontSize = fontSize > 0 + ? fontSize + : 10; + + // + string mFont = IsValid(font) + ? font + : "Arial"; + + // + ObjectSetString(0, tag, OBJPROP_FONT, mFont); + ObjectSetInteger(0, tag, OBJPROP_COLOR, clr); + ObjectSetInteger(0, tag, OBJPROP_ANCHOR, Anchor); + ObjectSetInteger(0, tag, OBJPROP_FONTSIZE, mFontSize); +} + +// +// END Functions ... +// + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.common.extensions.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: XCommonExtensionsLib +// Description: provide all commonly used functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../Classes/x-saherelm.x-md5.class.mq5" +#include "../Libraries/x-saherelm.x-enums.lib.mq5" + +// +#include + +// +// Constants ... +#define X_MIN_SIZE 0 +#define X_INVALID_INDEX -1 + +// +// START Value Checkers ... +// + +// +// Check a Value Not Empty ... +template +bool NotEmpty(T value) +{ + return value != EMPTY_VALUE; +} + +// +// Check a Value Not Empty and Zero ... +template +bool NotEmptyZero(T value) +{ + return value != 0 && + value != EMPTY_VALUE; +} + +// +// END Value Checkers ... +// + +// +// START Validators ... +// + +/** + * Validate Strings ... + * + * @param value: string + * + * @return ( bool ) + */ +bool IsValid(string value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + StringLen(value) > 0 + // + ; + + // + return result; +} +bool IsXValid(string value) +{ + return IsValid(value); +} +bool IsSpecifiedValid(string value) +{ + return IsValid(value); +} + +/** + * Validate Date ... + * + * @param value: datetime + * + * @return ( bool ) + */ +bool IsValid(datetime value) +{ + // + bool result = false; + + // + result = NotEmpty(value) && value != NULL; + + // + return result; +} +bool IsXValid(datetime value) +{ + return IsValid(value); +} +bool IsSpecifiedValid(datetime value) +{ + return IsValid(value); +} + +/** + * Validate Time Frame ... + * + * @param value: ENUM_TIMEFRAMES member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_TIMEFRAMES value) +{ + // + bool result = false; + + // + result = + // + value != NULL + // + ; + + // + return result; +} +bool IsXValid(ENUM_TIMEFRAMES value) +{ + // + return IsValid(value); +} +bool IsSpecifiedValid(ENUM_TIMEFRAMES value) +{ + // + return IsValid(value); +} + +/** + * Validate Specific Period Mode ... + * + * @param mMethod: ENUM_X_PERIOD_METHOD member, Period Select Method ... + * @param mPeriod: ENUM_TIMEFRAMES member, Selected Period ... + * + * @return ( bool ) + */ +bool IsValid( + ENUM_X_PERIOD_METHOD mMethod, + ENUM_TIMEFRAMES mPeriod // +) +{ + // + bool result = false; + + // + result = + // + mMethod == X_PERIOD_NONE + ? false + : mMethod == X_PERIOD_MANUALLY + ? mPeriod != NULL + : mMethod == X_PERIOD_AUTO + ? true + : false + // + ; + + // + return result; +} +bool IsXValid( + ENUM_X_PERIOD_METHOD mMethod, + ENUM_TIMEFRAMES mPeriod // +) +{ + return IsValid( + mMethod, + mPeriod // + ); +} +bool IsSpecifiedValid( + ENUM_X_PERIOD_METHOD mMethod, + ENUM_TIMEFRAMES mPeriod // +) +{ + return IsValid( + mMethod, + mPeriod // + ); +} + +/** + * Validate a Size Value ... + * + * @param value: int, Provided Size ... + * + * @return ( bool ) + */ +bool IsValidSize(int value) +{ + // + bool result = value > X_MIN_SIZE; + + // + return result; +} + +/** + * Check a Given Index is Valid or not ... + * + * @param value: int, Provided Index ... + * + * @return ( bool ) + */ +bool IsValidIndex(int value) +{ + return value >= X_MIN_SIZE; +} + +// +// END Validators ... +// + +// +// START Normalizations ... +// + +/** + * Normalize Symbol ... + * + * @param value: string, Provided Symbols ... + * + * @return ( string ) + */ +string NormalizeSymbol(string value) +{ + // + string result = value; + + // + if (!IsValid(result)) + { + result = _Symbol; + } + + // + return result; +} + +/** + * Normalize Time ... + * + * @param value: datetime, Provided Time ... + * + * @return ( datetime ) + */ +datetime NormalizeTime(datetime value) +{ + // + datetime result = value; + + // + if (!IsValid(result)) + { + result = TimeCurrent(); + } + + // + return result; +} + +/** + * Normalize Period ... + * + * @param value: ENUM_TIMEFRAMES member, Provided Period ... + * + * @return ( ENUM_TIMEFRAMES ) + */ +ENUM_TIMEFRAMES NormalizePeriod(ENUM_TIMEFRAMES value) +{ + // + ENUM_TIMEFRAMES result = value; + + // + if (!IsValid(value)) + { + result = _Period; + } + + // + return result; +} + +/** + * Normalize Market Cycle ... + * + * @param value: ENUM_X_MARKET_CYCLES, Provided Cycle ... + * + * @return ( ENUM_X_MARKET_CYCLES ) + */ +ENUM_X_MARKET_CYCLES NormalizeCycle(ENUM_X_MARKET_CYCLES value) +{ + // + ENUM_X_MARKET_CYCLES result = value; + + // + if (!IsValid(result)) + { + result = X_MARKET_CYCLE_SHORT; + } + + // + return value; +} + +/** + * Normalize Price Boundary ... + * + * @param value: ENUM_X_BOUNDARY_PRICE, Provided Boundary Mode ... + * + * @return ( ENUM_X_BOUNDARY_PRICE ) + */ +ENUM_X_BOUNDARY_PRICE NormalizeBoundary(ENUM_X_BOUNDARY_PRICE value) +{ + // + ENUM_X_BOUNDARY_PRICE result = value; + + // + if (!IsValid(result)) + { + result = X_BOUNDARY_PRICE_HIGH_LOW; + } + + // + return result; +} + +/** + * Normalize Integer Value ... + * + * @param value: int, Provided Value ... + * @param min: int, Minimum Allowed Value ... + * @param max: int, Maximum Allowed Value ... + * + * @return ( int ) + */ +int NormalizeInt( + int value, + int min = 0, + int max = INT_MAX // +) +{ + // + if (value < min) + { + value = min; + } + + // + if (value > max) + { + value = max; + } + + // + return value; +} + +/** + * Normalize Double Value ... + * + * @param value: double, Provided Value ... + * @param min: double, Minimum Allowed Value ... + * @param max: double, Maximum Allowed Value ... + * + * @return ( double ) + */ +double NormalizeDouble( + double value, + double min = 0, + double max = DBL_MAX // +) +{ + // + if (value < min) + { + value = min; + } + + // + if (value > max) + { + value = max; + } + + // + return value; +} +double NormalizeXDouble( + double value, + double min = 0, + double max = DBL_MAX // +) +{ + return NormalizeDouble(value, min, max); +} + +/** + * Normalize Index based on Collection ... + * + * @param index: int, Provided Index ... + * @param buffer: Collection Reference ... + */ +template +bool NormalizeIndex( + int &index, + T &buffer[] // +) +{ + // + bool result = false; + + // + int size = ArraySize(buffer); + result = IsValidSize(size); + if (!result) + { + return result; + } + + // + if (!IsValidIndex(index)) + { + index = X_MIN_SIZE; + } + + // + if (index > size - 1) + { + index = size - 1; + } + + // + result = IsValidIndex(index) && + index >= X_MIN_SIZE && + index < size; + + // + return result; +} + +/** + * Normalize Start and Count based on Specified Buffer ... + * + * @param start: int, Provided Start index ... + * @param count: int, Provided Number of Iteration ... + * @param buffer: Collection instance ... + */ +template +void NormalizeCount( + int &start, + int &count, + T &buffer[] // +) +{ + // + // Validate Buffer Size ... + int bufferSize = ArraySize(buffer); + if (!IsValidSize(bufferSize)) + { + return; + } + + // + // Normalization Start ... + NormalizeIndex( + start, + buffer // + ); + + // + if (count < start) + { + count = (start - count); + } + + // + // Normalization Count ... + + // + if (count < 0) + { + count = start; + } + + // + if (count > bufferSize - start) + { + count = bufferSize - start; + } +} + +/** + * Normalize a Volume ... + * + * @param mVolume: double, Provided Volume ... + * @param mSymbol: string, Specified Symbol ... + * @param mLength: int, Provided Default floating Length ... + * + * @return ( double ) + */ +double NormalizeVolume( + double mVolume, + string mSymbol = NULL, + int mLength = 2 // +) +{ + // + double result = mVolume; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double maxAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MAX); + double minAvailableVolume = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_MIN); + + // + // Normalize Digits ... + int digits = GetDigits(minAvailableVolume); + + // + mLength = + mLength == 0 || mLength > digits + ? digits + : MathMin(mLength, digits); + + // + // Normalize Volume ... + result = NormalizeDouble(result, mLength); + + // + // Validate Result ... + if (result > maxAvailableVolume) + { + result = maxAvailableVolume; + } + else if (result < minAvailableVolume) + { + result = minAvailableVolume; + } + + // + return result; +} + +/** + * Normalize a Price Value ... + * + * @param mPrice: double, Provided Price ... + * @param mSymbol: string, Provided Symbol ... + * + * @return ( double ) + */ +double NormalizePrice( + double mPrice, + string mSymbol = NULL // +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double tickSize = 0; + result = SymbolInfoDouble(mSymbol, SYMBOL_TRADE_TICK_SIZE, tickSize); + + // + int digits = GetDigits(mSymbol); + result = NormalizeDouble(MathRound(mPrice / tickSize) * tickSize, digits); + + // + return result; +} + +/** + * Normalize Chart Id ... + * + * @param _chartId: ulong + * + * @return ( ulong ) + */ +ulong NormalizeChartId(ulong _chartId = 0) +{ + // + if (_chartId <= 0) + { + _chartId = ChartID(); + } + + // + return _chartId; +} + +// +// END Normalizations ... +// + +// +// START Position ... +// + +/** + * Determine a Position type is Long or not ... + * + * @param value: ENUM_POSITION_TYPE member, Specified Type ... + * + * @return ( bool ) + */ +bool IsLong(ENUM_POSITION_TYPE value) +{ + // + bool result = value == POSITION_TYPE_BUY; + + // + return result; +} + +/** + * Determine a Position type is Long or not ... + * + * @param value: ENUM_ORDER_TYPE member, Specified Type ... + * + * @return ( bool ) + */ +bool IsLong(ENUM_ORDER_TYPE value) +{ + // + bool result = value == ORDER_TYPE_BUY; + + // + return result; +} + +/** + * Determine a Position type is Long or not ... + * + * @param value: ENUM_X_DIRECTION member, Specified Type ... + * + * @return ( bool ) + */ +bool IsLong(ENUM_X_DIRECTION value) +{ + // + bool result = value == X_DIRECTION_BULLISH; + + // + return result; +} + +/** + * Determine a Position type is Short or not ... + * + * @param value: ENUM_POSITION_TYPE member, Specified Type ... + * + * @return ( bool ) + */ +bool IsShort(ENUM_POSITION_TYPE value) +{ + // + bool result = value == POSITION_TYPE_SELL; + + // + return result; +} + +/** + * Determine a Position type is Short or not ... + * + * @param value: ENUM_ORDER_TYPE member, Specified Type ... + * + * @return ( bool ) + */ +bool IsShort(ENUM_ORDER_TYPE value) +{ + // + bool result = value == ORDER_TYPE_SELL; + + // + return result; +} + +/** + * Determine a Position type is Short or not ... + * + * @param value: ENUM_X_DIRECTION member, Specified Type ... + * + * @return ( bool ) + */ +bool IsShort(ENUM_X_DIRECTION value) +{ + // + bool result = value == X_DIRECTION_BEARISH; + + // + return result; +} + +/** + * Converts Opposit Direction Type ... + * + * @param value: ENUM_POSITION_TYPE member, Specified Type ... + * + * @return ( ENUM_POSITION_TYPE ) + */ +ENUM_POSITION_TYPE Opposit(ENUM_POSITION_TYPE value) +{ + // + ENUM_POSITION_TYPE result = NULL; + + // + bool isLong = IsLong(value); + result = isLong + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + + // + return result; +} + +/** + * Converts Opposit Direction Type ... + * + * @param value: ENUM_ORDER_TYPE member, Specified Type ... + * + * @return ( ENUM_ORDER_TYPE ) + */ +ENUM_ORDER_TYPE Opposit(ENUM_ORDER_TYPE value) +{ + // + ENUM_ORDER_TYPE result = NULL; + + // + bool isLong = IsLong(value); + result = isLong + ? ORDER_TYPE_SELL + : ORDER_TYPE_BUY; + + // + return result; +} + +/** + * Converts To String ... + * + * @param value: ENUM_POSITION_TYPE member ... + * + * @return ( string ) + */ +string ToXString(ENUM_POSITION_TYPE value) +{ + // + string result = NULL; + + // + result = + // + IsLong(value) + ? "Long" + : "Short" + // + ; + + // + return result; +} + +/** + * Converts To String ... + * + * @param value: ENUM_ORDER_TYPE member ... + * + * @return ( string ) + */ +string ToXString(ENUM_ORDER_TYPE value) +{ + // + string result = NULL; + + // + result = + // + IsLong(value) + ? "Long" + : "Short" + // + ; + + // + return result; +} + +/** + * Get Ask Price ... + * + * @param mSymbol: string, Provided Symbol ... + * + * @return ( double ) + */ +double GetAsk( + string mSymbol = NULL // +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_ASK); + + // + return result; +} + +/** + * Get Bid Price ... + * + * @param mSymbol: string, Provided Symbol ... + * + * @return ( double ) + */ +double GetBid( + string mSymbol = NULL // +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_BID); + + // + return result; +} + +/** + * Get Spread Price ... + * + * @param mSymbol: string, Provided Symbol ... + * + * @return ( double ) + */ +double GetSpread( + string mSymbol = NULL // +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double ask = GetAsk(mSymbol); + double bid = GetBid(mSymbol); + + // + double result = MathAbs(ask - bid); + + // + return result; +} +double GetXSpread( + string mSymbol = NULL // +) +{ + return GetSpread(mSymbol); +} + +/** + * Get SPecified Symbols Volume Step ... + * + * @param mSymbol: string ... + * + * @return ( double ) + */ +double GetVolumeStep( + string mSymbol = NULL // +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_VOLUME_STEP); + + // + return result; +} + +/** + * Get Point Price ... + * + * @param mSymbol: string, Provided Symbol ... + * + * @return ( double ) + */ +double GetPoints( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double result = SymbolInfoDouble(mSymbol, SYMBOL_POINT); + + // + return result; +} +double GetXPoints(string mSymbol = NULL) +{ + return GetPoints(mSymbol); +} + +/** + * Converts Price to Point ... + * + * @param price: double, price ... + * @param mSymbol: string, Symbol ... + * + * @return ( double ) + */ +double PriceToPoint( + double mPrice, // the price amount which required to calculate + string mSymbol = NULL // Trading Symbol +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPrice = NormalizePrice(mPrice, mSymbol); + + // + double point = GetPoints(mSymbol); + result = mPrice / point; + + // + return result; +} + +/** + * Get Digits Length ... + * + * @param mSymbol: string, Provided Symbol ... + * + * @return ( double ) + */ +int GetDigits( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + int result = (int)SymbolInfoInteger(mSymbol, SYMBOL_DIGITS); + + // + return result; +} + +/** + * Get Entry Price ... + * + * @param mSymbol: string, Provided Symbol ... + * @param type: ENUM_POSITION_TYPE member, Specified Entry type ... + * + * @return ( double ) + */ +double GetEntry( + string mSymbol = NULL, + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetAsk(mSymbol) + : GetBid(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} +double GetXEntry( + string mSymbol = NULL, + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // +) +{ + return GetEntry(mSymbol, type); +} + +/** + * Get Entry Price ... + * + * @param mSymbol: string, Provided Symbol ... + * @param type: ENUM_X_DIRECTION member, Specified Entry type ... + * + * @return ( double ) + */ +double GetEntry( + string mSymbol = NULL, + ENUM_X_DIRECTION type = X_DIRECTION_BULLISH // +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsBullish(type) + ? GetAsk(mSymbol) + : GetBid(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} +double GetXEntry( + string mSymbol = NULL, + ENUM_X_DIRECTION type = X_DIRECTION_BULLISH // +) +{ + return GetEntry(mSymbol, type); +} + +/** + * Get Exit Price ... + * + * @param mSymbol: string, Provided Symbol ... + * @param type: ENUM_POSITION_TYPE member, Specified Exit type ... + * + * @return ( double ) + */ +double GetExit( + string mSymbol = NULL, + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsLong(type) + ? GetBid(mSymbol) + : GetAsk(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} +double GetXExit( + string mSymbol = NULL, + ENUM_POSITION_TYPE type = POSITION_TYPE_BUY // +) +{ + return GetExit(mSymbol, type); +} + +/** + * Get Exit Price ... + * + * @param mSymbol: string, Provided Symbol ... + * @param type: ENUM_X_DIRECTION member, Specified Exit type ... + * + * @return ( double ) + */ +double GetExit( + string mSymbol = NULL, + ENUM_X_DIRECTION type = X_DIRECTION_BULLISH // +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + + // + result = + IsBullish(type) + ? GetBid(mSymbol) + : GetAsk(mSymbol); + result = NormalizePrice(result, mSymbol); + + // + return result; +} +double GetXExit( + string mSymbol = NULL, + ENUM_X_DIRECTION type = X_DIRECTION_BULLISH // +) +{ + return GetExit(mSymbol, type); +} + +/** + * Retrieve Current Tick ... + */ +bool GetTick( + string mSymbol, + MqlTick &tick // +) +{ + return SymbolInfoTick(mSymbol, tick); +} + +// +// Peak and Vales ... + +int FindXSwing( + ENUM_X_SWING_TYPE mType, + string mSymbol = NULL, + ENUM_TIMEFRAMES mPeriod = NULL, + int mFromIndex = 0, + int mShoulders = 5 // +) +{ + // + int result = -1; + + // + // Validate ... + if (!IsXValid(mType)) + { + return result; + } + + // + result = mFromIndex; + int foundedIDX = FindXNextSwing( + mType, + mSymbol, + mPeriod, + result - mShoulders, + mShoulders * 2 + 1 // + ); + while (foundedIDX != result) + { + // + result = FindXNextSwing( + mType, + mSymbol, + mPeriod, + result + 1, + mShoulders // + ); + + // + foundedIDX = FindXNextSwing( + mType, + mSymbol, + mPeriod, + result - mShoulders, + mShoulders * 2 + 1 // + ); + } + + // + return result; +} + +int FindXNextSwing( + ENUM_X_SWING_TYPE mType, + string mSymbol = NULL, + ENUM_TIMEFRAMES mPeriod = NULL, + int mFromIndex = 0, + int mShoulders = 5 // +) +{ + // + int result = -1; + + // + if (mFromIndex < 0) + { + mShoulders += mFromIndex; + } + + // + // Normalize ... + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + mFromIndex = NormalizeInt(mFromIndex, 0); + mShoulders = NormalizeInt(mShoulders, 3); + + // + // Validate .... + if (!IsXValid(mType)) + { + return result; + } + + // + // Converts Swing Type to Series Mode ... + ENUM_SERIESMODE mMode = ToSeriesMode(mType); + result = + mMode == MODE_HIGH + ? iHighest( + mSymbol, + mPeriod, + mMode, + mShoulders, + mFromIndex // + ) + : iLowest( + mSymbol, + mPeriod, + mMode, + mShoulders, + mFromIndex // + ); + + // + return result; +} + +// +// END Position ... +// + +// +// START Tools ... +// + +/** + * Check Expert Running in Testing Mode or not ... + * + * @return ( bool ) + */ +bool IsRunningOnTestMode() +{ + // + bool result = false; + + // + // check programm mode ... + result = MQLInfoInteger(MQL_TESTER); + + // + return result; +} + +/** + * Check Expert Running in Visual Testing Mode ... + * + * @return ( bool ) + */ +bool IsRunningeOnTestVisualMode() +{ + // + bool result = false; + + // + result = IsRunningOnTestMode() && + MQLInfoInteger(MQL_VISUAL_MODE); + + // + return result; +} + +/** + * Find Chart ID ... + * + * @param mSymbol: string, Specified Symbol ... + * @param mPeriod: ENUM_TIMEFRAMES member, Specified Period ... + * + * @return ( long ) + */ +long FindChartID( + string mSymbol = NULL, + ENUM_TIMEFRAMES mPeriod = NULL // +) +{ + // + long result = ChartFirst(); + long first = result; + + // + while (result > 0) + { + // + string chSymbol = ChartSymbol(result); + ENUM_TIMEFRAMES chPeriod = ChartPeriod(result); + + // + bool isOwn = + // + chSymbol == mSymbol && + chPeriod == mPeriod + // + ; + if (isOwn) + { + break; + } + + // + result = ChartNext(result); + } + + // + return result; +} + +/** + * Retrieve Available Symbols ... + * + * @param symbols: string Collection reference to Hold Symbols ... + * @param onlyInWatchList: bool, Force Extracts only Watch List Symbols ... + * + * @return ( int ) + */ +int GetAllSymbols( + string &symbols[], // Hold Result + bool onlyInWatchList = false // Specified Retrieve only Symbols which in Watch List +) +{ + // + int result = 0; + + // + Clean(symbols); + + // + int count = SymbolsTotal(onlyInWatchList); + if (!IsValidSize(count)) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + string iSymbol = SymbolName( + i, + onlyInWatchList // + ); + if (!IsValid(iSymbol)) + { + continue; + } + + // + Add( + iSymbol, + symbols // + ); + } + + // + result = ArraySize(symbols); + + // + return result; +} + +/** + * Filter Symbols Collections ... + * + * @param query: string, Provided Query to Search Symbols ... + * @param symbols: string, Collection resources to Hold's Filtered results ... + * @param onlyInWatchList: bool, Specified Apply Filter only on Watch List Symbols ... + * @param ignoreCase: bool, Ignore Case Sesitive ... + * @param querySeparator: string, Provided Separator of Query ... + * + * @return ( int ) + */ +int FilterSymbols( + string query, + string &symbols[], + bool onlyInWatchList = false, + bool ignoreCase = true, + string querySeparator = "," // If Provided means query is a Collection of Queries and need to be Splitted +) +{ + // + int result = 0; + + // + Clean(symbols); + + // + if (!IsValid(query)) + { + return result; + } + + // + // Check Query is an String array or not ... + string mQueries[]; + int queriesCount = 0; + if (IsValid(querySeparator) && Contains(querySeparator, query, true)) + { + // + queriesCount = SplitContent( + mQueries, + query, + querySeparator // + ); + } + + // + string allSymbols[]; + int allSymbolsCount = GetAllSymbols( + allSymbols, + onlyInWatchList // + ); + if (allSymbolsCount <= 0) + { + return result; + } + + // + // Loop Through all Symbols ... + for (int i = 0; i < allSymbolsCount; i++) + { + // + string iSymbol = allSymbols[i]; + + // + bool isFilterPassed = false; + if (queriesCount == 0) + { + // + isFilterPassed = Contains( + query, + iSymbol, + ignoreCase // + ); + } + else if (queriesCount > 0) + { + // + isFilterPassed = Contains( + mQueries, + iSymbol, + ignoreCase // + ); + } + + // + if (isFilterPassed) + { + // + Add( + iSymbol, + symbols // + ); + } + } + + // + result = ArraySize(symbols); + + // + return result; +} + +/** + * Extract Symbols to Find Only USD Side Assets ... + * + * @param symbols: string, Collection resources to Hold's Filtered results ... + * @param onlyInWatchList: bool, Specified Apply Filter only on Watch List Symbols ... + * @param ignoreCase: bool, Ignore Case Sesitive ... + * @param querySeparator: string, Provided Separator of Query ... + * + * @return ( int ) + */ +int FilterUSDSymbols( + string &symbols[], + bool onlyInWatchList = false, + bool ignoreCase = true, + string querySeparator = "," // +) +{ + // + return FilterSymbols( + "USD", + symbols, + onlyInWatchList, + ignoreCase, + querySeparator // + ); +} + +/** + * Get Digits Length of Specified Double Value ... + * + * @param value: double, Provided Value ... + * + * @return ( int ) + */ +int GetDigits(double value) +{ + // + int d = 0; + double p = 1; + while (MathRound(value * p) / p != value) + { + p = MathPow(10, ++d); + } + + // + return d; +} + +/** + * Retrieve Specific Object Types Name ... + * + * @param t: T object reference ... + * + * @return ( string ) + * + */ +template +string GetTypeName(const T &t) +{ + return typename(T); +} +template +string GetTypeName(const T *t) +{ + return typename(T); +} + +/** + * Get Specified Types Token ... + * + * @param item: T, object reference ... + * + * @return ( string ) + */ +template +string GetToken(T &item) +{ + // + string mType = GetTypeName(item); + + // + string result = mType; + + // + string parts[]; + int partsCount = SplitContent( + parts, + result, + " " // + ); + if (partsCount <= 0) + { + // + result = mType; + return result; + } + + // + bool hasLastPart = GetLastItem( + result, + parts // + ); + if (!hasLastPart) + { + // + result = mType; + return result; + } + + // + return result; +} +template +string GetSpecificToken(T &item) +{ + return GetToken(item); +} + +/** + * Generate Unique Tags ... + * + * @param model: T, object reference ... + * + * @return ( string ) + */ +template +string GenerateTag(T &model) +{ + // + string result = ""; + + // + string tag = model.ToXString(); + if (StringLen(tag) == 0) + { + return result; + } + + // + XSCMD5 *md5; + md5 = new XCMD5(); + + // + result = md5.Hash(tag); + + // + ZeroMemory(md5); + + // + return result; +} + +/** + * Hash Specified Content ... + * + * @param content: T, Proveded Content ... + * + * @return ( string ) + */ +template +string ToMD5(T content) +{ + // + string result = ""; + + // + string strContent = ToXString(content); + if (StringLen(strContent) == 0) + { + return result; + } + + // + XCMD5 *md5; + md5 = new XCMD5(); + + // + result = md5.Hash(strContent); + + // + delete md5; + ZeroMemory(md5); + + // + return result; +} + +/** + * Calculate Fibo Level ... + * + * @param mUp: double, Specified Upper Price ... + * @param mDown: double, Specified Lower Price ... + * @param mLevel: ENUM_X_FIBO_LEVELS member, Specified Fibo Level ... + * @param mForDir: ENUM_X_DIRECTION member, Specified Calculation Direction ... + * + * @return ( double ) + */ +double GetFibonacciLevel( + double mUp, + double mDown, + ENUM_X_FIBO_LEVELS mLevel, + ENUM_X_DIRECTION mForDir // +) +{ + // + double result = 0; + + // + double levelValue = GetFiboLevelValue(mLevel); + + // + bool isValid = + // + mUp > 0 && + mDown > 0 && + levelValue > 0 && + mUp > mDown && + HasDirection(mForDir) + // + ; + if (!isValid) + { + return result; + } + + // + bool isBullish = IsBullish(mForDir); + + // + double ling = mUp - mDown; + double pLevel = (ling / 100) * (levelValue * 100); + + // + result = + isBullish + ? mUp - pLevel + : mDown + pLevel; + + // + return result; +} + +/** + * Calculate Sspecified Buffer's Moving Averages ... + * + * @param rates_total: Integer, number of items ... + * @param prev_calculated: Integer, Previous Calculate Items ... + * @param begin: Integer, Bar Index ... + * @param period: Integer, Moving Average Length ... + * @param source: Double Array, Specified Array for Calculating Moving Averages ... + * @param buffer: Double Array, Specified Array to Apply Calculated Moving Average on it ... + * @param method: ENUM_MA_METHOD member Specified Moving Average Calculation Method ... + * + * @return ( int ) + */ +int iMAOnBuffer( + const int _rates_total, + const int _prev_calculated, + const int _begin, + const int _period, + const double &_source[], + double &_buffer[], + ENUM_X_MA_METHOD _method = X_MA_MODE_SMA // +) +{ + // + int result = 0; + + // + if ( + _period < 0 || + _rates_total <= 0 || + _prev_calculated < 0 || + _method == X_MA_MODE_NONE || + _prev_calculated > _rates_total) + { + return result; + } + + // + switch (_method) + { + // + case X_MA_MODE_SMA: + result = SimpleMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + + // + case X_MA_MODE_EMA: + result = ExponentialMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + + // + case X_MA_MODE_LWMA: + result = LinearWeightedMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + + // + case X_MA_MODE_SMMA: + result = SmoothedMAOnBuffer( + _rates_total, + _prev_calculated, + _begin, + _period, + _source, + _buffer // + ); + break; + } + + // + return result; +} + +// +// END Tools ... +// + +// +// START String ... +// + +/** + * Search a Content Contains Specific String or not ... + * + * @param mQuery: string, Search Query ... + * @param mContent: string, Search Content ... + * @param ignoreCase: bool, Force Ignore Case Sensitive ... + * + * @return ( bool ) + */ +bool Contains( + string mQuery, + string mContent, + bool ignoreCase = true // +) +{ + // + bool result = false; + + // + // Validate Query ... + result = IsValid(mQuery); + if (!result) + { + return result; + } + + // + // Validate Content ... + result = IsValid(mContent); + if (!result) + { + return result; + } + + // + // Normalize Inputs ... + string query = mQuery; + string content = mContent; + if (ignoreCase) + { + // + StringToLower(query); + StringToLower(content); + } + + // + int queryIdx = StringFind( + content, + query); + + // + result = queryIdx >= 0; + + // + return result; +} + +/** + * Search a Content Contains Specifics Query or not ... + * + * @param mQueries: string collection, Search Queries ... + * @param mContent: string, Search Content ... + * @param ignoreCase: bool, Force Ignore Case Sensitive ... + * + * @return ( bool ) + */ +bool Contains( + string &mQueries[], + string mContent, + bool ignoreCase = true // +) +{ + // + bool result = false; + + // + // Validate Queries ... + int queriesCount = ArraySize(mQueries); + result = queriesCount > 0; + if (!result) + { + return result; + } + + // + // Validate Content ... + result = IsValid(mContent); + if (!result) + { + return result; + } + + // + int containsCount = 0; + for (int i = 0; i < queriesCount; i++) + { + // + bool isContains = Contains( + mQueries[i], + mContent, + ignoreCase); + + // + if (!isContains) + { + // + result = false; + break; + } + + // + containsCount++; + } + + // + result = containsCount == queriesCount; + + // + return result; +} + +/** + * Search a Content and Extract Occuranse Indexes ... + * + * @param mQuery: string, Search Query ... + * @param mContent: string, Search Content ... + * @param result: int collection reference, Holds Founded Indexes ... + * @param ignoreCase: bool, Force Ignore Case Sensitive ... + * + * @return ( int ) + */ +int FindIndexes( + string mQuery, + string mContent, + int &result[], + bool ignoreCase = false // +) +{ + // + int mResult = 0; + + // + Clean(result); + + // + // Validate Inputs ... + if (!IsValid(mQuery) || + !IsValid(mContent)) + { + return mResult; + } + + // + // Apply Ignore Case if Provided ... + if (ignoreCase) + { + // + bool isConverted = StringToLower(mQuery); + if (!isConverted) + { + return mResult; + } + + // + isConverted = StringToLower(mContent); + if (!isConverted) + { + return mResult; + } + } + + // + // Search First Index ... + int lastPos = 0; + int idx = StringFind( + mContent, + mQuery, + lastPos // + ); + while (idx >= 0) + { + // + // Add Position to Result ... + Add( + idx, + result // + ); + + // + lastPos = idx + StringLen(mQuery); + idx = StringFind( + mContent, + mQuery, + lastPos // + ); + } + + // + mResult = ArraySize(result); + + // + return mResult; +} +int FindXIndexes( + string mQuery, + string mContent, + int &result[], + bool ignoreCase = false // +) +{ + return FindXIndexes(mQuery, mContent, result, ignoreCase); +} + +/** + * Convert From String ... + * + * @param value: string, Provided Value ... + * + * @return ( T ) + */ +template +T FromString(string value) +{ + // + T result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + result = (T)value; + + // + return result; +} + +/** + * Converts to String ... + * + * @param value: T, Provided Value ... + * + * @return ( string ) + */ +template +string ToXString(T value) +{ + return (string)value; +} + +string Trim(string value) +{ + // + string result = NULL; + + // + result = value; + + // + StringTrimRight(result); + StringTrimLeft(result); + + // + return result; +} + +// +// Used In Report or Summary Generators ... +string ToXString( + string prefix, // Title + bool value, // Value + bool ignoreFalseConditions = true, // Ignore False Conditions + string lineSeparator = "\n", // Line Separator + string prefixSeparator = ":" // Title Separator +) +{ + // + string result = NULL; + + // + bool canSet = + IsBoolean(ToXString(value)) + ? (bool)value || !ignoreFalseConditions + : true; + + // + result = canSet + ? prefix + + prefixSeparator + " " + + ToXString(value) + + lineSeparator + : ""; + + // + return result; +} + +// +template +string ToXString( + string prefix, // Title + T value, // Value + string lineSeparator = "\n", // Line Separator + string prefixSeparator = ":" // Title Separator +) +{ + // + string result = NULL; + + // + result = prefix + + prefixSeparator + " " + + ToXString(value) + + lineSeparator; + + // + return result; +} + +// +string SetLabel( + string mLabel, // Provided Label ... + string value, // Source Value ... + string separator = "\n", // Line Separator + bool addTopEmptyLine = true // Add Empty Line On top +) +{ + // + string result = value; + + // + if (StringLen(mLabel) <= 0) + { + return result; + } + + // + result = (StringLen(value) > 0) + ? (addTopEmptyLine ? separator : "") + + mLabel + + separator + + "-----------------------------" + + separator + + value + : value; + + // + return result; +} + +// +// Converts a Buffer to String Representation ... +template +string ToXString( + const T &buffer[], // Specified Buffer + string separator = ",", // Specified Separator + bool addIndex = false, // Specified Add Items Indexes or Not + string indexLabel = "i:", // Specified Index Label + string indexSeparator = ">" // Specified Index Separator +) +{ + // + string result = ""; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + for (int i = 0; i < bufferSize; i++) + { + // + if (addIndex) + { + // + if (StringLen(indexLabel) > 0) + { + result += indexLabel + " "; + } + + // + result += (string)i + " "; + + // + if (StringLen(indexSeparator) > 0) + { + result += indexSeparator + " "; + } + } + + // + string iItemString = (string)buffer[i]; + + // + result += iItemString; + + // + if (i < bufferSize - 1) + { + result += separator; + } + } + + // + return result; +} + +/** + * Check a String Value is Boolean or Not ... + * + * @param value: string representation of value ... + * + * @return ( bool ) + */ +bool IsBoolean(string value) +{ + // + bool result = false; + + // + string istring = value; + string normalizedValue = ToXString(istring); + StringToLower(normalizedValue); + normalizedValue = Trim(normalizedValue); + + // + result = + !IsValid(normalizedValue) + ? false + : (normalizedValue == "true" || + normalizedValue == "false"); + + // + return result; +} + +/** + * Converts String to boolean ... + * + * @param value: string, Provided Value ... + * + * @return ( bool ) + */ +bool ToBoolean(string value) +{ + // + bool result = false; + + // + if (!IsBoolean(value) || + StringLen(value) <= 0) + { + return result; + } + + // + value = Trim(value); + StringToLower(value); + + // + bool isTrue = value == "true"; + bool isFalse = value == "false"; + + // + result = isTrue + ? true + : false; + + // + return result; +} + +// +// Split an String Representation of an Array ... +int SplitContent( + string &result[], // Hold Result ... + string content, // Source ... + string separator = ",", // Separator ... + bool forceCleanResult = true // Clean Result ... +) +{ + // + int mResult = 0; + + // + if (forceCleanResult) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + if (separator == NULL || StringLen(separator) == 0) + { + separator = ","; + } + + // + if (StringLen(content) == 0) + { + return mResult; + } + + // + StringSplit( + content, + StringGetCharacter( + separator, + 0), + result); + + // + int after = ArraySize(result); + + // + mResult = after - before; + + // + return mResult; +} + +// +// Extract Data from String ... +string ExtractString( + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = ""; + + // + // Validate String ... + if ( + StringLen(source) == 0 || + StringLen(endString) == 0 || + StringLen(startString) == 0) + { + return result; + } + + // + // Find Start String Position ... + int sPos = StringFind( + source, + startString); + if (sPos < 0) + { + return result; + } + + // + // Find End String Position after Start String ... + int searchEndFromPos = sPos + StringLen(startString); + int ePos = StringFind( + source, + endString, + searchEndFromPos); + if (ePos < 0) + { + return result; + } + + // + // Extract Data from Source ... + int dLength = ePos - searchEndFromPos; + result = StringSubstr( + source, + searchEndFromPos, + dLength); + + // + return result; +} + +// +// Extract an Array of Contents ... +int ExtractStrings( + string &result[], // Hold Result + const string source, // Source String used for Extracting + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int mResult = 0; + + // + Clean(result); + + // + // Validate Args ... + int sourceLength = StringLen(source); + int startLength = StringLen(startString); + int endLength = StringLen(endString); + + // + int minRequiredLength = startLength + endLength; + + // + if ( + endLength <= 0 || + startLength <= 0 || + sourceLength <= 0 || + sourceLength < minRequiredLength) + { + return mResult; + } + + // + // Make a Copy of Source for Manipulating ... + string workStr = source; + + // + // Define a Loop ... + while (StringLen(workStr) > minRequiredLength) + { + // + // Find Item ... + string item = ExtractString( + workStr, + startString, + endString); + + // + // Breakout when couldn't find anymore item ... + int itemLength = StringLen(item); + if (itemLength <= 0) + { + break; + } + + // + // Prepare Item Source String for Replacing in Work String ... + string itemSource = startString + item + endString; + + // + // Add Item to Result Array ... + Add( + item, + result); + + // + // Replace Item Soure in Work String ... + StringReplace( + workStr, + itemSource, + ""); + } + + // + // Calculate Size of Array ... + mResult = ArraySize(result); + + // + return mResult; +} + +// +string ExtractSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + return ExtractString( + surrounded, + mToken + startString, + endString + // + ); +} + +// +int ParseIntSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + int result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (int)strContent; + + // + return result; +} + +long ParseLongSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + long result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (long)strContent; + + // + return result; +} + +string ParseStringSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + string result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (string)strContent; + + // + return result; +} + +double ParseDoubleSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + double result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (double)strContent; + + // + return result; +} + +datetime ParseTimeSurrounded( + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + const string startString = "(", // Expression Start String must be Unique + const string endString = ")" // Where to End Extraction, usually a Sign +) +{ + // + datetime result = NULL; + + // + string strContent = ExtractSurrounded( + surrounded, + mToken, + startString, + endString + // + ); + if (!IsValid(strContent)) + { + return result; + } + + // + result = (datetime)strContent; + + // + return result; +} + +// +int ParseIntArraySurrounded( + int &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + int iValue = (int)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} + +int ParseLongArraySurrounded( + long &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + long iValue = (long)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} + +int ParseDoubleArraySurrounded( + double &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + double iValue = (double)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} + +int ParseTimeArraySurrounded( + datetime &result[], // Holds Result + const string surrounded, // Surrounded Content + const string mToken, // Specified Token + string separator = ",", // Separator ... + const string startString = "(", // Expression Start String must be Unique + const string endString = ")", // Where to End Extraction, usually a Sign + bool forceClean = true // Clean Result ... +) +{ + // + int count = 0; + + // + if (forceClean) + { + Clean(result); + } + + // + int before = ArraySize(result); + + // + string contentStr = ParseStringSurrounded(surrounded, mToken); + if (!IsValid(contentStr)) + { + return count; + } + + // + string tmps[]; + int tmpsCount = SplitContent( + tmps, + contentStr + // + ); + if (tmpsCount <= 0) + { + return count; + } + + // + for (int i = 0; i < tmpsCount; i++) + { + // + string iTMP = tmps[i]; + if (!IsValid(iTMP)) + { + continue; + } + + // + datetime iValue = (datetime)iTMP; + + // + Add( + iValue, + result + // + ); + } + + // + int after = ArraySize(result); + + // + count = after - before; + + // + return count; +} + +// +// Surround an String by Specific Token ... +template +string Surround( + string mToken, // an String which used to Tokenize + T &value, // a Value for Tokenize it + string startString = "(", // Token Start Content + string endString = ")" // Token End Content +) +{ + // + string result = NULL; + + // + string strValue = ToXString(value); + if (!IsValid(strValue)) + { + return result; + } + + // + result = + // + (IsValid(mToken) + ? mToken + : "") + + // + startString + + strValue + + endString + // + ; + + // + return result; +} + +// +template +string SurroundArray( + string mToken, + T &value[], + string startString = "(", // Token Start Content + string endString = ")" // Token End Content +) +{ + // + string result = NULL; + + // + string valueStr = ToXString(value); + if (!IsValid(valueStr)) + { + return result; + } + + // + result = Surround( + mToken, + valueStr, + startString, + endString + // + ); + + // + return result; +} + +// +// END String ... +// + +// +// START Cycles ... +// + +/** + * Converts String To Period ... + * + * @param value: string ... + * + * @return ( ENUM_TIMEFRAMES ) + */ +ENUM_TIMEFRAMES ToPeriod(string value) +{ + // + if (StringLen(value) == 0) + { + return _Period; + } + + // + StringTrimLeft(value); + StringTrimRight(value); + + // + ENUM_TIMEFRAMES result = _Period; + + // + if (value == "M1") + { + result = PERIOD_M1; + } + else if (value == "M2") + { + result = PERIOD_M2; + } + else if (value == "M3") + { + result = PERIOD_M3; + } + else if (value == "M4") + { + result = PERIOD_M4; + } + else if (value == "M5") + { + result = PERIOD_M5; + } + else if (value == "M6") + { + result = PERIOD_M6; + } + else if (value == "M10") + { + result = PERIOD_M10; + } + else if (value == "M12") + { + result = PERIOD_M12; + } + else if (value == "M15") + { + result = PERIOD_M15; + } + else if (value == "M20") + { + result = PERIOD_M20; + } + else if (value == "M30") + { + result = PERIOD_M30; + } + else if (value == "H1") + { + result = PERIOD_H1; + } + else if (value == "H2") + { + result = PERIOD_H2; + } + else if (value == "H3") + { + result = PERIOD_H3; + } + else if (value == "H4") + { + result = PERIOD_H4; + } + else if (value == "H6") + { + result = PERIOD_H6; + } + else if (value == "H8") + { + result = PERIOD_H8; + } + else if (value == "H12") + { + result = PERIOD_H12; + } + else if (value == "D1") + { + result = PERIOD_D1; + } + else if (value == "W1") + { + result = PERIOD_W1; + } + else if (value == "MN1") + { + result = PERIOD_MN1; + } + + // + return result; +} + +/** + * Converts To String ... + * + * @param value: ENUM_TIMEFRAMES member ... + * + * @return ( string ) + */ +string ToXString(ENUM_TIMEFRAMES value) +{ + // + string result = ""; + + // + string mPStr = EnumToString(value); + + string mPStrParts[]; + int partsCount = StringSplit( + mPStr, + StringGetCharacter("_", 0), + mPStrParts); + if (partsCount <= 0) + { + return result; + } + + // + result = mPStrParts[1]; + + // + return result; +} + +// +// Retrieve All Available Period as an Array ...s +int GetAllAvailablePeriods( + ENUM_TIMEFRAMES &result[] // Holds Result ... +) +{ + // + Clean(result); + + // + Add( + PERIOD_M1, + result + // + ); + + // + Add( + PERIOD_M2, + result + // + ); + + // + Add( + PERIOD_M3, + result + // + ); + + // + Add( + PERIOD_M4, + result + // + ); + + // + Add( + PERIOD_M5, + result + // + ); + + // + Add( + PERIOD_M6, + result + // + ); + + // + Add( + PERIOD_M10, + result + // + ); + + // + Add( + PERIOD_M12, + result + // + ); + + // + Add( + PERIOD_M15, + result + // + ); + + // + Add( + PERIOD_M20, + result + // + ); + + // + Add( + PERIOD_M30, + result + // + ); + + // + Add( + PERIOD_H1, + result + // + ); + + // + Add( + PERIOD_H2, + result + // + ); + + // + Add( + PERIOD_H3, + result + // + ); + + // + Add( + PERIOD_H4, + result + // + ); + + // + Add( + PERIOD_H6, + result + // + ); + + // + Add( + PERIOD_H8, + result + // + ); + + // + Add( + PERIOD_H12, + result + // + ); + + // + Add( + PERIOD_D1, + result + // + ); + + // + Add( + PERIOD_W1, + result + // + ); + + // + Add( + PERIOD_MN1, + result + // + ); + + // + int mResult = ArraySize(result); + + // + return mResult; +} + +// +// Get Specific Time Frame Start Candle Time ... +datetime GetPeriodStartTime( + string mSymbol = NULL, // Specified Symbol ... + ENUM_TIMEFRAMES mPeriod = NULL, // Specified Period ... + datetime mTime = NULL // Specified Bar Time of Host Period ... +) +{ + // + // Normalize Arg ... + mTime = NormalizeTime(mTime); + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false // + ); + + // + datetime result = GetBarTime( + mSymbol, + mPeriod, + barIndex // + ); + + // + return result; +} + +// +// Retrieve Nearest Period base on Given Period ... +ENUM_TIMEFRAMES GetNearestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_M5; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_M10; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_M20; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H1; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H3; + break; + + // + case PERIOD_H3: + result = PERIOD_H4; + break; + + // + case PERIOD_H4: + result = PERIOD_H6; + break; + + // + case PERIOD_H6: + result = PERIOD_H8; + break; + + // + case PERIOD_H8: + result = PERIOD_H12; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Mediest Period base on Given Period ... +ENUM_TIMEFRAMES GetMediestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_M10; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_M15; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_M30; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H2; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H4; + break; + + // + case PERIOD_H3: + result = PERIOD_H6; + break; + + // + case PERIOD_H4: + result = PERIOD_H8; + break; + + // + case PERIOD_H6: + result = PERIOD_H12; + break; + + // + case PERIOD_H8: + result = PERIOD_D1; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Longest Period base on Given Period ... +ENUM_TIMEFRAMES GetLongestPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_M30; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_H1; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_H2; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H4; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H6; + break; + + // + case PERIOD_H3: + result = PERIOD_H8; + break; + + // + case PERIOD_H4: + result = PERIOD_H12; + break; + + // + case PERIOD_H6: + result = PERIOD_D1; + break; + + // + case PERIOD_H8: + result = PERIOD_W1; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Hindmost Period base on Given Period ... +ENUM_TIMEFRAMES GetHindMostPeriod(ENUM_TIMEFRAMES mPeriod) +{ + // + ENUM_TIMEFRAMES result = _Period; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + case PERIOD_M2: + case PERIOD_M3: + result = PERIOD_H1; + break; + + // + case PERIOD_M4: + case PERIOD_M5: + case PERIOD_M6: + result = PERIOD_H2; + break; + + // + case PERIOD_M10: + case PERIOD_M12: + case PERIOD_M15: + result = PERIOD_H4; + break; + + // + case PERIOD_M20: + case PERIOD_M30: + result = PERIOD_H6; + break; + + // + case PERIOD_H1: + case PERIOD_H2: + result = PERIOD_H8; + break; + + // + case PERIOD_H3: + result = PERIOD_H12; + break; + + // + case PERIOD_H4: + result = PERIOD_D1; + break; + + // + case PERIOD_H6: + result = PERIOD_W1; + break; + + // + case PERIOD_H8: + result = PERIOD_MN1; + break; + + // + default: + result = mPeriod; + break; + } + + // + return result; +} + +// +// Retrieve Specified Cycles Period related to Host Period ... +ENUM_TIMEFRAMES GetCyclePeriod( + ENUM_X_MARKET_CYCLES mCycle = NULL, // Specified Cycle + ENUM_TIMEFRAMES mPeriod = NULL // Host Period +) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + mPeriod = NormalizePeriod(mPeriod); + mCycle = NormalizeCycle(mCycle); + + // + switch (mCycle) + { + // + // Short ... + case X_MARKET_CYCLE_SHORT: + result = GetNearestPeriod(mPeriod); + break; + + // + // Medium ... + case X_MARKET_CYCLE_MEDIUM: + result = GetMediestPeriod(mPeriod); + break; + + // + // Long ... + case X_MARKET_CYCLE_LONG: + result = GetLongestPeriod(mPeriod); + break; + + // + // Hind ... + case X_MARKET_CYCLE_HIND: + result = GetHindMostPeriod(mPeriod); + break; + } + + // + return result; +} + +// +// Calculate a Cycle Length based on Host Period ... +int GetCycleLengthOn( + ENUM_TIMEFRAMES _hostPeriod, + ENUM_X_MARKET_CYCLES _cycle, + ENUM_X_PERIOD_METHOD _method, + ENUM_TIMEFRAMES _period // +) +{ + // + int result = 0; + + // + // Validate ... + bool isValid = + // + IsValid(_hostPeriod) && + IsValid(_method, _Period) + // + ; + if (!isValid) + { + return result; + } + + // + // Calculate Period ... + isValid = + _method != X_PERIOD_NONE && + _cycle != X_MARKET_CYCLE_UNKNOWN; + if (!isValid) + { + return result; + } + + // + if (_method == X_PERIOD_AUTO) + { + // + _period = GetCyclePeriod( + _cycle, + _hostPeriod // + ); + } + isValid = IsValid(_period); + if (!isValid) + { + return result; + } + + // + int _hostPeriodSeconds = PeriodSeconds(_hostPeriod); + int _periodSeconds = PeriodSeconds(_period); + + // + isValid = _periodSeconds >= _hostPeriodSeconds; + if (!isValid) + { + return result; + } + + // + result = _periodSeconds / _hostPeriodSeconds; + + // + return result; +} + +/** + * Retrieve Sharp Change Info for Specified Period ... + * + * @param priceChange: double, required Price Change ... + * @param mPeriod: ENUM_TIMEFRAMES member, Specified Period ... + * + * @return ( int ) + */ +int GetPeriodSharpData( + double &priceChange, + ENUM_TIMEFRAMES mPeriod = NULL // +) +{ + // + int result = 0; + + // + priceChange = 0.0; + + // + mPeriod = NormalizePeriod(mPeriod); + + // + switch (mPeriod) + { + // + case PERIOD_M1: + // + priceChange = 0.000006; + result = 14; + break; + + // + case PERIOD_M2: + // + priceChange = 0.000006; + result = 14; + break; + + // + case PERIOD_M3: + // + priceChange = 0.00007; + result = 14; + break; + + // + case PERIOD_M4: + // + priceChange = 0.000007; + result = 14; + break; + + // + case PERIOD_M5: + // + priceChange = 0.000009; + result = 14; + break; + + // + case PERIOD_M6: + // + priceChange = 0.000009; + result = 14; + break; + + // + case PERIOD_M10: + // + priceChange = 0.00001; + result = 12; + break; + + // + case PERIOD_M12: + // + priceChange = 0.000011; + result = 11; + break; + + // + case PERIOD_M15: + // + priceChange = 0.000011; + result = 9; + break; + + // + case PERIOD_M20: + // + priceChange = 0.000012; + result = 9; + break; + + // + case PERIOD_M30: + // + priceChange = 0.000012; + result = 7; + break; + + // + case PERIOD_H1: + // + priceChange = 0.000013; + result = 5; + break; + + // + case PERIOD_H2: + // + priceChange = 0.000013; + result = 5; + break; + + // + case PERIOD_H3: + // + priceChange = 0.000014; + result = 5; + break; + + // + case PERIOD_H4: + // + priceChange = 0.000014; + result = 5; + break; + + // + case PERIOD_H6: + // + priceChange = 0.000015; + result = 5; + break; + + // + case PERIOD_H8: + // + priceChange = 0.000017; + result = 5; + break; + + // + case PERIOD_H12: + // + priceChange = 0.000017; + result = 5; + break; + + // + case PERIOD_D1: + // + priceChange = 0.000019; + result = 3; + break; + + // + case PERIOD_W1: + // + priceChange = 0.00002; + result = 3; + break; + + // + case PERIOD_MN1: + // + priceChange = 0.000021; + result = 3; + break; + } + + // + return result; +} + +// +// END Cycles ... +// + +// +// START Collections ... +// + +// +// Add Specified Item to Array ... +template +int Add( + T item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} +template +int AddSpecified( + T item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + return Add( + item, + buffer // + ); +} +template +int AddRef( + T &item, // item want to add + T &buffer[] // Destination buffer +) +{ + // + int result = 0; + + // + ArrayResize( + buffer, + ArraySize(buffer) + 1); + + // + buffer[ArraySize(buffer) - 1] = item; + + // + result = ArraySize(buffer); + + // + return result; +} + +// +// Check Specified Array Has Childs or not ... +template +bool HasChild(T &buffer[]) +{ + return IsValidSize(ArraySize(buffer)); +} +template +bool SpecifiedHasChild(T &buffer[]) +{ + return HasChild(buffer); +} + +// +// Remove Specified Item from an Array ... +template +bool Remove( + T item, + T &buffer[] // +) +{ + // + bool result = false; + + // + int itemIndex = FindIndex( + item, + buffer); + if (itemIndex < 0) + { + return result; + } + + // + result = ArrayRemove( + buffer, + itemIndex, + 1); + + // + return result; +} + +// +// Clean Specified Array ... +template +void Clean(T &buffer[]) +{ + // + if (!HasChild(buffer)) + { + return; + } + + // + // ArrayResize(buffer, 0); + ArrayFree(buffer); + ZeroMemory(buffer); +} +template +void SpecifiedClean(T &buffer[]) +{ + Clean(buffer); +} +template +void XClean(T &buffer[]) +{ + Clean(buffer); +} + +// +// Copy Whole Content of Source to Dest array ... +template +void Copy( + T &source[], // Source Buffer ... + T &dest[], // Dest Buffer ... + bool cleanDest = true // Force Clen Dest Buffer ... +) +{ + // + if (cleanDest) + { + Clean(dest); + } + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + AddRef( + iSource, + dest); + } +} + +// +// Copy Items from a Buffer ... +template +int Copy( + int start, // Start + int count, // Number of Items for read + T &source[], // Source Buffer + T &dest[], // Dest Buffer + bool forceClean = true, // Force To Clean buffer + bool forceStart = true // Force To Clean buffer +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(dest); + } + + // + if (start < 0 && forceStart) + { + start = 0; + } + + // + if (start >= ArraySize(source)) + { + start = ArraySize(source) - 1; + } + + // + if (count == 0) + { + count = ArraySize(source) - 1 - start; + } + + // + if (start + count > ArraySize(source)) + { + return result; + } + + // + int beforeSize = ArraySize(dest); + + // + bool asSeriesDest = ArrayGetAsSeries(dest); + bool asSeriesSource = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(dest, true); + ArraySetAsSeries(source, true); + + // + ArrayCopy( + dest, + source, + 0, + start, + count + // + ); + + // + int afterSize = ArraySize(dest); + + // + result = afterSize - beforeSize; + + // + ArraySetAsSeries(dest, asSeriesDest); + ArraySetAsSeries(source, asSeriesSource); + + // + return result; +} + +// +// Copy Items from a Buffer ... +template +int CopyRef( + int start, // Start + int count, // Number of Items for read + T &source[], // Source Buffer + T &dest[], // Dest Buffer + bool forceClean = true // Force To Clean buffer +) +{ + // + int result = 0; + + // + if (forceClean) + { + Clean(dest); + } + + // + if (start < 0) + { + start = 0; + } + + // + if (start >= ArraySize(source)) + { + start = ArraySize(source) - 1; + } + + // + int beforeSize = ArraySize(dest); + + // + bool asSeriesDest = ArrayGetAsSeries(dest); + bool asSeriesSource = ArrayGetAsSeries(source); + + // + ArraySetAsSeries(dest, true); + ArraySetAsSeries(source, true); + + // + for (int i = start; i < start + count; i++) + { + // + AddRef( + source[i], + dest + // + ); + } + + // + int afterSize = ArraySize(dest); + + // + result = afterSize - beforeSize; + + // + ArraySetAsSeries(dest, asSeriesDest); + ArraySetAsSeries(source, asSeriesSource); + + // + return result; +} + +// +// Retrive Last Item of Specified Buffer ... +template +bool GetLastItem( + T &item, // Holds Result + T &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + if (bufferSize <= 0) + { + return result; + } + + // + item = buffer[bufferSize - 1]; + + // + result = true; + return result; +} + +// +// Remove Last Item of Specified Buffer ... +template +bool RemoveLastItem( + T &buffer[] // Specified Buffer +) +{ + // + bool result = false; + + // + int count = ArraySize(buffer); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + ArrayRemove( + buffer, + count - 1, + 1 // + ); + + // + return result; +} + +template +void CleanupArray( + T &buffer[], // Buffer to Cleanup ... + int maxAllowed = 0 // Max Allowed Number of items ... +) +{ + // + if (maxAllowed <= 0) + { + return; + } + + // + int count = ArraySize(buffer); + if (!IsValidSize(count) || + count <= maxAllowed) + { + return; + } + + // + int mustRemove = count - maxAllowed; + if (!IsValidSize(mustRemove)) + { + return; + } + + // + ArrayRemove( + buffer, + 0, + mustRemove // + ); +} + +template +void CleanupArray( + int &removedIndexes[], + T &buffer[] // Buffer to Cleanup ... +) +{ + // + bool isValid = HasChild(buffer) && + HasChild(removedIndexes); + if (!isValid) + { + return; + } + + // + for (int i = 0; i < ArraySize(removedIndexes); i++) + { + // + int idx = removedIndexes[i]; + if (IsValidIndex(idx) && ArraySize(buffer) > idx) + { + // + ArrayRemove( + buffer, + idx, + 1 // + ); + } + } + + // + Clean(removedIndexes); +} + +// +// Search Array For Specific Item ... +template +int FindIndex( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + int result = -1; + + // + int count = ArraySize(buffer); + if (count <= 0) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + T iT = buffer[i]; + + // + if (iT == item) + { + // + result = i; + break; + } + } + + // + return result; +} +template +int FindXIndex( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + return FindIndex(item, buffer); +} + +// +// Find Specific Item Index inside a Collection ... +template +int FindIndex( + T &item, // Item to Find + const T &items[] // Items for Search +) +{ + // + int result = -1; + + // + // Check Item Validation ... + if (!item.IsValid()) + { + return result; + } + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < itemsCount; i++) + { + // + T iItem = items[i]; + + // + // Validate Item ... + if (!iItem.IsValid()) + { + continue; + } + + // + bool isSame = item.IsSameAs(iItem); + if (isSame && result <= -1) + { + // + result = i; + break; + } + } + + // + return result; +} +template +int FindXIndex( + T &item, // Item to Find + const T &items[] // Items for Search +) +{ + return FindIndex(item, items); +} + +// +// Check an Array Contains Specified Value ... +template +bool Contains( + T item, // What is Search ... + T &buffer[] // Search in ... +) +{ + // + bool result = false; + + // + int idx = FindIndex( + item, + buffer); + result = idx > -1; + + // + return result; +} + +// +// Calculate a Buffer's Sum ... +template +double GetSum( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Calculate Summary ... + for (int i = 0; i < tmpCount; i++) + { + result += buffer[i]; + } + + // + return result; +} + +// +// Calculate a Buffer's Average ... +template +double GetAverage( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + double result = 0; + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Calculate Summary ... + for (int i = 0; i < tmpCount; i++) + { + result += buffer[i]; + } + + // + // Calculate Average ... + result = result / tmpCount; + + // + return result; +} + +// +// Get Max of Specific Loopback of a Buffer ... +template +T GetMax( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + result = + // + result == 0 || result < iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} +template +T GetMaxWidthIndex( + T &buffer[], // the Buffer which required to search + int &index, // Item Index ... + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + index = -1; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + bool isNew = result == 0; + bool canSet = isNew || + (!isNew && + result < iValue); + if (canSet) + { + // + index = i; + result = iValue; + } + } + + // + return result; +} +template +T GetSpecifiedMax( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMax( + buffer, + start, + count // + ); +} +template +T GetSpecifiedMaxWidthIndex( + T &buffer[], // the Buffer which required to search + int &index, // Item Index ... + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMaxWidthIndex( + buffer, + index, + start, + count // + ); +} + +// +// Get Min of Specific Loopback of a Buffer ... +template +T GetMin( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + result = + // + result == 0 || result > iValue + // + ? iValue + // + : result + // + ; + } + + // + return result; +} +template +T GetMinWidthIndex( + T &buffer[], // the Buffer which required to search + int &index, // Item Index ... + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + // + T result = 0; + index = -1; + + // + if (count <= 0) + { + count = ArraySize(buffer); + } + + // + T tmp[]; + int tmpCount = Copy( + start, + count, + buffer, + tmp + // + ); + if (tmpCount <= 0) + { + return result; + } + + // + // Loop Through LoopBack ... + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + bool isNew = result == 0; + bool canSet = isNew || + (!isNew && + result > iValue); + if (canSet) + { + // + index = i; + result = iValue; + } + } + + // + return result; +} +template +T GetSpecifiedMin( + T &buffer[], // the Buffer which required to search + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMin( + buffer, + start, + count // + ); +} +template +T GetSpecifiedMinWidthIndex( + T &buffer[], // the Buffer which required to search + int &index, // Item Index ... + int start = 0, // Start Index + int count = 0 // Count for Search +) +{ + return GetMinWidthIndex( + buffer, + index, + start, + count // + ); +} + +// +// Find a Value less than Specified ... +template +T FindLesserThan( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Biggest Lesser Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source) // + ); + + // + ArrayCopy( + tmp, + source // + ); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue < value) + { + // + result = iValue; + break; + } + } + + // + return result; +} +template +T FindLesserThanByIndex( + T value, // Specified Value ... + int &index, // Item Index ... + const T &source[], // Source ... + bool isDescend = false // Find Biggest Lesser Value ... +) +{ + // + T result = -1; + index = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source) // + ); + + // + ArrayCopy( + tmp, + source // + ); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue < value) + { + // + index = i; + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find a Value less than Specified ... +template +T FindBiggerThan( + T value, // Specified Value ... + const T &source[], // Source ... + bool isDescend = false // Find Smallest Bigger Value ... +) +{ + // + T result = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source) // + ); + + // + ArrayCopy( + tmp, + source // + ); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (!isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue > value) + { + // + result = iValue; + break; + } + } + + // + return result; +} +template +T FindBiggerThanByIndex( + T value, // Specified Value ... + int &index, // Item Index ... + const T &source[], // Source ... + bool isDescend = false // Find Smallest Bigger Value ... +) +{ + // + T result = -1; + index = -1; + + // + int itemsCount = ArraySize(source); + if (itemsCount <= 0) + { + return result; + } + + // + // Make a Copy of source ... + T tmp[]; + + // + ArrayResize( + tmp, + ArraySize(source) // + ); + + // + ArrayCopy( + tmp, + source // + ); + + // + // Sort Temp Buffer ... + ArraySort(tmp); + if (!isDescend) + { + ArrayReverse(tmp); + } + + // + int tmpCount = ArraySize(tmp); + for (int i = 0; i < tmpCount; i++) + { + // + T iValue = tmp[i]; + + // + if (iValue > value) + { + // + index = i; + result = iValue; + break; + } + } + + // + return result; +} + +// +// Find Same Values in Array ... +template +void FindSames( + T &result[], // Holds Result ... + T &source[], // Source ... + int verifications = 3 // Number of Consequence Repeat ... +) +{ + // + Clean(result); + + // + // TenkanSen Flats ... + int sourceCount = ArraySize(source); + if (sourceCount > verifications) + { + // + T mLast = 0; + int mVerified = 0; + for (int i = 0; i < sourceCount; i++) + { + // + T iVal = source[i]; + if (mLast == 0) + { + mLast = iVal; + } + else if (mLast == iVal) + { + mVerified++; + } + else + { + mLast = iVal; + mVerified = 0; + } + + // + if (iVal == mLast && mVerified >= verifications) + { + // + Add( + iVal, + result); + + // + mLast = 0; + mVerified = 0; + } + } + } +} + +// +// Add an Item to a Buffer if not Exists ... +void AddIfNotExists( + double value, + double &values[], + double smoothingPoint = 3 // +) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int valuesCount = ArraySize(values); + if (valuesCount <= 0) + { + // + Add(value, + values); + } + else + { + // + bool isExists = false; + for (int i = 0; i < valuesCount; i++) + { + // + double iVal = values[i]; + + // + double diff = MathAbs(iVal - value); + + // + if (iVal == value || diff < smoothingValue) + { + // + isExists = true; + break; + } + } + + // + if (!isExists) + { + // + Add(value, + values); + } + } +} + +// +// Add a Buffers Child to another Buffer +// if it's not Contains them ... +void AddsIfNotExists( + double &source[], + double &dest[], + double smoothingPoint = 3 // +) +{ + // + double smoothingValue = smoothingPoint * GetPoints(_Symbol); + + // + int sourceCount = ArraySize(source); + if (sourceCount <= 0) + { + return; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + double iSource = source[i]; + + // + AddIfNotExists( + iSource, + dest, + smoothingPoint); + } +} + +// +// END Collections ... +// + +// +// START Buffers ... +// + +bool IsSame( + double current, + double previous, + double tolerance = 2 // +) +{ + // + bool result = + NotEmptyZero(current) && + NotEmptyZero(previous) && + current <= previous + tolerance && + current >= previous + tolerance; + + // + return result; +} + +bool IsOver( + double current, + double previous, + double tolerance = 2 // +) +{ + // + bool result = + NotEmptyZero(current) && + NotEmptyZero(previous) && + current >= previous + tolerance; + + // + return result; +} + +bool IsUnder( + double current, + double previous, + double tolerance = 2 // +) +{ + // + bool result = + NotEmptyZero(current) && + NotEmptyZero(previous) && + current <= previous - tolerance; + + // + return result; +} + +// +template +bool IsSame( + T &buffer[], // Search Buffer + int count = 5, // Number of Searchs + int start = 0 // Start ... +) +{ + // + bool result = false; + + // + int bufferSize = ArraySize(buffer); + result = bufferSize > 0; + if (!result) + { + return result; + } + + // + // Validate Count ... + result = start + count < bufferSize; + if (!result) + { + return result; + } + + // + T iTem = buffer[start]; + for (int i = start; i < start + count; i++) + { + // + if (iTem != buffer[i]) + { + result = false; + break; + } + + // + if (!result) + { + result = true; + } + } + + // + return result; +} + +// +// Check first Cross Over second at index ... +bool IsCrossedOver( + const double &first[], // the buffer which check crossing over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + !(first[index + 1] > second[index + 1]); + + // + return result; +} + +// +// Check first is Over second at index ... +bool IsOver( + const double &first[], // the buffer which check over second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] > second[index] && + first[index + 1] > second[index + 1]; + + // + return result; +} + +// +// Check first Cross Under second at index ... +bool IsCrossedUnder( + const double &first[], // the buffer which check crossing under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + !(first[index + 1] < second[index + 1]); + + // + return result; +} + +// +// Check first is Under second at index ... +bool IsUnder( + const double &first[], // the buffer which check under second buffer + const double &second[], // first buffer checks based on this buffer + const int index = 0 // check crosses in specific index +) +{ + // + bool result = false; + + // + // Validate Args ... + if (ArraySize(first) < index + 1 || ArraySize(second) < index + 1) + { + return result; + } + + // + result = first[index] < second[index] && + first[index + 1] < second[index + 1]; + + // + return result; +} + +// +// Check if a Value Increasing in Loopback ... +bool IsIncreasing( + const double &buffer[], // the Buffer which required to search + int from = -1, // Last Time Index + int to = -1 // Fisrs Tima Index +) +{ + // + bool result = false; + + // + if (from == -1) + { + from = ArraySize(buffer) - 1; + } + + // + if (to == -1) + { + to = 0; + } + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue >= fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue >= iValue; + + // + bool isIIncreasing = IsIncreasing( + buffer, + from, + i // + ); + + // + // Check Result ... + result = result && isPassed && isIIncreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +// Check if a Value Decreasing in Loopback ... +bool IsDecreasing( + const double &buffer[], // the Buffer which required to search + int from = -1, // Last Time Index + int to = -1 // Fisrs Tima Index +) +{ + // + bool result = false; + + // + if (from == -1) + { + from = ArraySize(buffer) - 1; + } + + // + if (to == -1) + { + to = 0; + } + + // + // Validate Args ... + if ( + from <= to || + ArraySize(buffer) < from + 1) + { + return result; + } + + // + // Loop through Items ... + double toValue = buffer[to]; + double fromValue = buffer[from]; + result = toValue <= fromValue; + for (int i = to + 1; i <= from - 1; i++) + { + // + double iValue = buffer[i]; + bool isPassed = toValue <= iValue; + + // + bool isIDecreasing = IsDecreasing( + buffer, + from, + i // + ); + + // + // Check Result ... + result = result && isPassed && isIDecreasing; + if (!result) + { + break; + } + } + + // + return result; +} + +// +bool IsTrendingUp( + const double &buffer1[], // First Buffer + const double &buffer2[] // Seccend Buffer +) +{ + // + bool result = false; + + // + int buffer1Count = ArraySize(buffer1); + int buffer2Count = ArraySize(buffer2); + if (buffer1Count <= 0 || buffer2Count <= 0) + { + return result; + } + + // + int count = MathMin(buffer1Count, buffer2Count); + if (count <= 1) + { + return result; + } + + // + int upCounts = 0; + int downCounts = 0; + double value = MathAbs(buffer1[0] - buffer2[0]); + for (int i = 1; i < count; i++) + { + // + double iValue = MathAbs(buffer1[i] - buffer2[i]); + + // + if (value > iValue) + { + upCounts++; + } + + // + if (value < iValue) + { + downCounts++; + } + } + + // + result = upCounts > 1 && upCounts > downCounts; + + // + return result; +} + +// +bool IsTrendingDown( + const double &buffer1[], // First Buffer + const double &buffer2[] // Seccend Buffer +) +{ + // + bool result = false; + + // + int buffer1Count = ArraySize(buffer1); + int buffer2Count = ArraySize(buffer2); + if (buffer1Count <= 0 || buffer2Count <= 0) + { + return result; + } + + // + int count = MathMin(buffer1Count, buffer2Count); + if (count <= 1) + { + return result; + } + + // + int upCounts = 0; + int downCounts = 0; + double value = MathAbs(buffer1[0] - buffer2[0]); + for (int i = 1; i < count; i++) + { + // + double iValue = MathAbs(buffer1[i] - buffer2[i]); + + // + if (value > iValue) + { + upCounts++; + } + + // + if (value < iValue) + { + downCounts++; + } + } + + // + result = downCounts > 1 && downCounts > upCounts; + + // + return result; +} + +// +// Calculate Slope of Specified Buffer at Specified Index ... +double GetSlope( + const double &buffer[], // Buffer + int from, // In Past Index ... + int to // In Past Index ... +) +{ + // + double result = 0; + + // + if (from > ArraySize(buffer) || to > ArraySize(buffer)) + { + return result; + } + + // + double toValue = buffer[to]; + double fromValue = buffer[from]; + double deltaValue = toValue - fromValue; + double deltaTime = from - to; + + // + result = deltaValue / deltaTime; + + // + return result; +} + +// +// END Buffers ... +// + +// +// START Time ... +// + +// +// Converts Time to Seconds ... +ulong TimeToSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = (ulong)time; + + // + return result; +} +ulong TimeToSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToSeconds(dTime); + + // + return result; +} + +// +// Converts Seconds To Time ... +datetime SecondsToTime( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime result = (datetime)seconds; + + // + return result; +} +MqlDateTime SecondsToStruct( + ulong seconds // Specify Seconds to Convert ... +) +{ + // + datetime dTime = SecondsToTime(seconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Converts Time to MilliSeconds ... +ulong TimeToMilliSeconds( + datetime time // Specify time to Convert ... +) +{ + // + ulong result = TimeToSeconds(time) * 1000; + + // + return result; +} +ulong TimeToMilliSeconds( + MqlDateTime &time // Specify time to Convert ... +) +{ + // + datetime dTime = StructToTime(time); + + // + ulong result = TimeToMilliSeconds(dTime); + + // + return result; +} + +// +// Converts MillisSeconds to Time ... +datetime MilliSecondsToTiem( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + ulong seconds = milliSeconds / 1000; + + // + datetime result = SecondsToTime(seconds); + + // + return result; +} +MqlDateTime MilliSecondsToStruct( + ulong milliSeconds // Specify MilliSeconds to Convert ... +) +{ + // + datetime dTime = MilliSecondsToTiem(milliSeconds); + + // + MqlDateTime result = {}; + TimeToStruct( + dTime, + result); + + // + return result; +} + +// +// Converts Hours to Seconds ... +int HoursToSeconds(int value) +{ + // + int result = 0; + + // + if (value < 0) + { + value = 0; + } + + // + if (value == 0) + { + return result; + } + + // + result = value * 60 * 60; + + // + return result; +} + +// +// Retrieve DateTime Structure ... +MqlDateTime GetCurrentTime() +{ + // + MqlDateTime result = {}; + + // + datetime cTime = TimeCurrent(); + TimeToStruct(cTime, result); + + // + return result; +} + +// +// Retrieve Current Time as Seconds ... +ulong GetCurrentTimeAsSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToSeconds(time); + + // + return result; +} + +// +// Retrieve Current Time as MilliSeconds ... +ulong GetCurrentTimeAsMilliSeconds() +{ + // + datetime time = TimeCurrent(); + + // + ulong result = TimeToMilliSeconds(time); + + // + return result; +} + +// +int GetLocalOffset() +{ + // + MqlDateTime cTimeStruct; + datetime cTime = TimeCurrent(cTimeStruct); + + // + MqlDateTime cLTimeStruct; + datetime cLTime = TimeLocal(cLTimeStruct); + + // + cTimeStruct.sec = 0; + cTime = StructToTime(cTimeStruct); + + // + cLTimeStruct.sec = 0; + cLTime = StructToTime(cLTimeStruct); + + // + int result = ((int)cLTime - (int)cTime); + + // + return result; +} + +// +int GetUTCRequiredTimeOffset() +{ + // + int utcOffset = TimeGMTOffset(); + int localOffset = GetLocalOffset(); + + // + int result = utcOffset + localOffset; + + // + return result; +} + +// +datetime GetUTCTime( + datetime time = NULL, + bool applyTradeServerTime = false // +) +{ + // + datetime result = NULL; + + // + NormalizeTime(time); + + // + datetime cTime = TimeCurrent(); + datetime cTimeLocal = TimeLocal(); + + // + int cLocalOffset = ((int)cTimeLocal - (int)cTime); + int gmtOffset = TimeGMTOffset(); + int offsetDelte = gmtOffset + cLocalOffset; + int requiredUTCOffset = GetUTCRequiredTimeOffset(); + if (requiredUTCOffset > 0) + { + requiredUTCOffset = -1 * requiredUTCOffset; + } + + // + int timeSeconds = (int)time; + int resultSeconds = timeSeconds + requiredUTCOffset; + + // + result = (datetime)(resultSeconds); + + // + return result; +} + +// +// Retrieve only Hour and Minute as String ... +string GetTimeString( + datetime time = NULL // +) +{ + // + NormalizeTime(time); + + // + string result = NULL; + + // + MqlDateTime tStruct; + bool isStructed = TimeToStruct(time, tStruct); + if (!isStructed) + { + return result; + } + + // + string hour = ToXString(tStruct.hour); + hour = + StringLen(hour) == 1 + ? "0" + hour + : hour; + + // + string minute = ToXString(tStruct.min); + minute = + StringLen(minute) == 1 + ? "0" + minute + : minute; + + // + result = hour + ":" + minute; + + // + return result; +} + +// +// Converts a Date time to File Format ... +string ToFormatString( + datetime mTime, + string separator = "_" // +) +{ + // + string result = NULL; + + // + if (!IsValid(mTime)) + { + return result; + } + + // + MqlDateTime timeStruct; + bool isConverts = TimeToStruct( + mTime, + timeStruct // + ); + if (!isConverts) + { + return result; + } + + // + string year = ToXString(timeStruct.year); + string month = ToXString(timeStruct.mon); + string day = ToXString(timeStruct.day); + string hour = ToXString(timeStruct.hour); + string minute = ToXString(timeStruct.min); + string second = ToXString(timeStruct.sec); + + // + result = + // + // Year ... + year + separator + + // + // Month ... + (StringLen(month) == 1 + ? "0" + month + : month) + + separator + + // + // Day ... + (StringLen(day) == 1 + ? "0" + day + : day) + + separator + + // + // Hour ... + (StringLen(hour) == 1 + ? "0" + hour + : hour) + + separator + + // + // Minute ... + (StringLen(minute) == 1 + ? "0" + minute + : minute) + + separator + + // + // Seconds ... + (StringLen(second) == 1 + ? "0" + second + : second) + + separator + + // + "" + // + ; + + // + return result; +} + +/** + * Converts an String Represetation of Time (00:00) to Date Time .. + * + * @param value: String ... + * + * @return ( datetime ) + */ +datetime ParseDateTimeFromTimeString(string value) +{ + // + datetime result = NULL; + + // + if (!IsValid(value)) + { + return result; + } + + // + // Check Signalling Time ... + MqlDateTime cTime; + bool isTimeRecieved = TimeCurrent(cTime); + if (!isTimeRecieved) + { + return result; + } + + // + // Split ... + string parts[]; + int partsCount = SplitContent( + parts, + value, + ":" + // + ); + if (!IsValidSize(partsCount)) + { + return result; + } + + // + int hour = 0; + int minute = 0; + if (partsCount >= 1) + { + hour = (int)(parts[0]); + } + if (partsCount >= 2) + { + minute = (int)(parts[1]); + } + + // + cTime.day_of_week = 0; + cTime.day_of_year = 0; + + // + cTime.hour = hour; + cTime.min = minute; + + // + result = StructToTime(cTime); + + // + return result; +} + +// +// Check Specific Time in Range of another Time ... +bool IsTimeInRange( + datetime currentTime = NULL, + datetime startTime = NULL, + datetime stopTime = NULL // +) +{ + // + bool result = false; + + // + // Normallize Current Time ... + currentTime = NormalizeTime(currentTime); + + // + result = !IsValid(startTime) && + !IsValid(stopTime); + if (result) + { + return result; + } + + // + result = IsValid(startTime) && + IsValid(stopTime); + if (!result) + { + // + result = IsValid(startTime) && + currentTime >= startTime; + + // + return result; + } + + // + result = currentTime >= startTime && + currentTime < stopTime; + + // + return result; +} +bool IsTimeInRange( + datetime currentTime, + string startTime, + string endTime // +) +{ + // + bool result = false; + + // + result = IsValid(startTime) && + IsValid(endTime); + if (!result) + { + // + // Here Since there isnot provide any + // data source we pass result as true ... + result = true; + return result; + } + + // + // Converts String Representation to Time ... + datetime st = ParseDateTimeFromTimeString(startTime); + datetime et = ParseDateTimeFromTimeString(endTime); + + // + result = IsTimeInRange( + currentTime, + st, + et // + ); + + // + return result; +} + +// +// END Time ... +// + +// +// START Price ... +// + +// +// Get 1 Pip in Price Value ... +double GetPipPrice( + string mSymbol = NULL // Trading Symbol +) +{ + // + mSymbol = NormalizeSymbol(mSymbol); + + // + double symbolPoint = GetPoints(mSymbol); + int symbolDigits = GetDigits(mSymbol); + + // + double result = symbolPoint; + if (symbolDigits == 3 || symbolDigits == 5) + { + result *= 10; + } + + // + return result; +} + +/** + * Calculate Applied Price ... + * + * @param mType: ENUM_X_PRICE member, Price Type ... + * @param mOpen: double collection, Open Prices ... + * @param mHigh: double collection, High Prices ... + * @param mLow: double collection, Low Prices ... + * @param mClose: double collection, Close Prices ... + * @param barIndex: int, Index ... + * + * @return ( double ) + */ +double GetAppliedPrice( + ENUM_X_PRICE mType, // Type of Price Selection + const double &mOpen[], // Open Prices + const double &mHigh[], // High Preices + const double &mLow[], // Low Prices + const double &mClose[], // Close Prices + int barIndex // Bar Index +) +{ + // + double result = 0; + + // + switch (mType) + { + // + case X_PRICE_NONE: + result = 0; + break; + + // + case X_PRICE_HIGH: + result = mHigh[barIndex]; + break; + + // + case X_PRICE_OPEN: + result = mOpen[barIndex]; + break; + + // + case X_PRICE_CLOSE: + result = mClose[barIndex]; + break; + + // + case X_PRICE_LOW: + result = mLow[barIndex]; + break; + + // + case X_PRICE_UP: + result = MathMax(mOpen[barIndex], mClose[barIndex]); + break; + + // + case X_PRICE_DOWN: + result = MathMin(mOpen[barIndex], mClose[barIndex]); + break; + + // + case X_PRICE_MEDIAN: + result = ((mHigh[barIndex] + mLow[barIndex]) / 2.0); + break; + + // + case X_PRICE_BODY_MEDIAN: + result = ((mOpen[barIndex] + mClose[barIndex]) / 2.0); + break; + + // + case X_PRICE_TYPICAL: + result = ((mHigh[barIndex] + mLow[barIndex] + mClose[barIndex]) / 3.0); + break; + + // + case X_PRICE_WEIGHTED: + result = (((mHigh[barIndex] + mLow[barIndex] + mClose[barIndex] + mClose[barIndex]) / 4.0)); + break; + } + + // + return result; +} + +/** + * Calculate Applied Price ... + * + * @param mType: ENUM_X_PRICE member, Price Type ... + * @param mOpen: double, Open Price ... + * @param mHigh: double, High Price ... + * @param mLow: double, Low Price ... + * @param mClose: double, Close Price ... + * @param barIndex: int, Index ... + * + * @return ( double ) + */ +double GetAppliedPrice( + ENUM_X_PRICE mType, // Type of Price Selection + double mOpen, // Open Prices + double mHigh, // High Preices + double mLow, // Low Prices + double mClose // Close Prices +) +{ + // + double result = 0; + + // + switch (mType) + { + // + case X_PRICE_NONE: + result = 0; + break; + + // + case X_PRICE_HIGH: + result = mHigh; + break; + + // + case X_PRICE_OPEN: + result = mOpen; + break; + + // + case X_PRICE_CLOSE: + result = mClose; + break; + + // + case X_PRICE_LOW: + result = mLow; + break; + + // + case X_PRICE_UP: + result = MathMax(mOpen, mClose); + break; + + // + case X_PRICE_DOWN: + result = MathMin(mOpen, mClose); + break; + + // + case X_PRICE_MEDIAN: + result = ((mHigh + mLow) / 2.0); + break; + + // + case X_PRICE_BODY_MEDIAN: + result = ((mOpen + mClose) / 2.0); + break; + + // + case X_PRICE_TYPICAL: + result = ((mHigh + mLow + mClose) / 3.0); + break; + + // + case X_PRICE_WEIGHTED: + result = (((mHigh + mLow + mClose + mClose) / 4.0)); + break; + } + + // + return result; +} + +/** + * Calculate Applied Price ... + * + * @param mSymbol: string, Specified Symbol ... + * @param mPeriod: ENUM_TIMEFRAMES member, Specified PEriod ... + * @param barIndex: int, Specified Bar Index ... + * @param mType: ENUM_X_PRICE member, Specified Price Type ... + * + * @return ( double ) + */ +double GetAppliedPrice( + string mSymbol = NULL, // Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Period + int barIndex = 0, // Bar Index + ENUM_X_PRICE mType = X_PRICE_CLOSE // Type of Price Selection +) +{ + // + double result = 0; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + barIndex = NormalizeInt(barIndex, 0); + + // + bool has = IsValid(mType); + if (!has) + { + return result; + } + + // + double open = iOpen( + mSymbol, + mPeriod, + barIndex // + ); + + // + double high = iHigh( + mSymbol, + mPeriod, + barIndex // + ); + + // + double low = iLow( + mSymbol, + mPeriod, + barIndex // + ); + + // + double close = iClose( + mSymbol, + mPeriod, + barIndex // + ); + + // + // Retrieve Applied Price ... + result = GetAppliedPrice( + mType, + open, + high, + low, + close // + ); + + // + return result; +} + +/** + * Calculate Applied Price ... + * + * @param mSymbol: string, Specified Symbol ... + * @param mPeriod: ENUM_TIMEFRAMES member, Specified PEriod ... + * @param time: int, Specified Bar Time ... + * @param mType: ENUM_X_PRICE member, Specified Price Type ... + * + * @return ( double ) + */ +double GetAppliedPrice( + string mSymbol = NULL, // Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Period + datetime mTime = NULL, // Bar Time + ENUM_X_PRICE mType = X_PRICE_CLOSE // Type of Price Selection +) +{ + // + double result = 0; + + // + mTime = NormalizeTime(mTime); + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + bool has = IsValid(mType); + if (!has) + { + return result; + } + + // + int barIndex = GetBarIndex( + mSymbol, + mPeriod, + mTime // + ); + has = IsValidIndex(barIndex); + if (!has) + { + return result; + } + + // + // Retrieve Applied Price ... + result = GetAppliedPrice( + mSymbol, + mPeriod, + barIndex, + mType // + ); + + // + return result; +} + +/** + * Calculate Price Boundary ... + * + * @param upper: double collection reference, Upper Boundary ... + * @param lower: double collection reference, Lower Boundary ... + * @param mSymbol: string, Specified Symbol ... + * @param mPeriod: ENUM_TIMEFRAMES member, Specified PEriod ... + * @param mMode: ENUM_X_BOUNDARY_PRICE member, Specified Boundary Mode ... + * @param mLength: int, Loopback Length of Bondary ... + * @param barIndex: int, Specified Bar Index ... + * @return ( int ) + */ +int GetPriceBoundary( + double &upper[], // Upper Boundary + double &lower[], // Lower Boundary + string mSymbol = NULL, // Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Period + ENUM_X_BOUNDARY_PRICE mMode = NULL, // Boundary Mode + int mLength = 1, // Length + int barIndex = 0 // Bar Index +) +{ + // + int result = 0; + + // + Clean(upper); + Clean(lower); + + // + // Normalize Args ... + mMode = NormalizeBoundary(mMode); + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + mLength = NormalizeInt(mLength, 1); + barIndex = NormalizeInt(barIndex, 0); + + // + // Prepare Boundary Price Types ... + ENUM_X_PRICE upperType = + mMode == X_BOUNDARY_PRICE_UP_DOWN + ? X_PRICE_UP + : mMode == X_BOUNDARY_PRICE_HIGH_LOW + ? X_PRICE_HIGH + : X_PRICE_NONE; + ENUM_X_PRICE lowerType = + mMode == X_BOUNDARY_PRICE_UP_DOWN + ? X_PRICE_DOWN + : mMode == X_BOUNDARY_PRICE_HIGH_LOW + ? X_PRICE_LOW + : X_PRICE_NONE; + + // + // Check Boundary Type Validation ... + bool isValid = IsValid(lowerType) && + IsValid(upperType); + if (!isValid) + { + return result; + } + + // + // Loop through Loopbacks ... + int start = barIndex + mLength; + int end = barIndex; + for (int i = start; i >= end; i--) + { + // + double iUpper = GetAppliedPrice( + mSymbol, + mPeriod, + i, + upperType // + ); + double iLower = GetAppliedPrice( + mSymbol, + mPeriod, + i, + lowerType // + ); + + // + Add( + iUpper, + upper // + ); + + // + Add( + iLower, + lower // + ); + } + + // + result = ArraySize(upper); + + // + return result; +} + +/** + * Get Applied Price Buffer ... + * + * @param mType: ENUM_X_PRICE, Specified Price Type ... + * @param dest: double, Holds Destination Prices ... + * @param mOpen: double collection, Open Prices ... + * @param mHigh: double collection, High Prices ... + * @param mLow: double collection, Low Prices ... + * @param mClose: double collection, Close Prices ... + * + * @return ( int ) + */ +int GetAppliedPrice( + ENUM_X_PRICE mType, + double &dest[], + const double &mOpen[], // Open Prices + const double &mHigh[], // High Preices + const double &mLow[], // Low Prices + const double &mClose[] // Close Prices +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Check ArraySizes ... + int count = ArraySize(mOpen); + count = MathMin(count, ArraySize(mHigh)); + count = MathMin(count, ArraySize(mClose)); + count = MathMin(count, ArraySize(mLow)); + + // + // Validate ... + if (!IsValidSize(count)) + { + return result; + } + + // + // Loopback ... + for (int i = 0; i < count; i++) + { + // + double iPrice = GetAppliedPrice( + mType, + mOpen[i], + mHigh[i], + mLow[i], + mClose[i] // + ); + + // + Add( + iPrice, + dest // + ); + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// END Price ... +// + +// +// START Bar ... +// + +/** + * Retrieve Specific Bar's Time ... + * + * @param mSymbol: string, Provided Symbol ... + * @param mPeriod: ENUM_TIMEFRAMES member, Provided Period ... + * @param barIndex: int, Provided Bar Index ... + * + * @return ( datetime ) + */ +datetime GetBarTime( + string mSymbol = NULL, // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + int barIndex = 0 // Specify Bar Index +) +{ + // + // Validate and Normalize Args ... + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + // Retrieve Bar Time ... + datetime result = iTime( + mSymbol, + mPeriod, + barIndex // + ); + + // + return result; +} + +/** + * Retrieve Specific Bar's Index ... + * + * @param mSymbol: string, Provided Symbol ... + * @param mPeriod: ENUM_TIMEFRAMES member, Provided Period ... + * @param barTime: datetime, Provided Bar Time ... + * + * @return ( datetime ) + */ +int GetBarIndex( + string mSymbol = NULL, // Specify Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Specify TimeFrame + datetime barTime = NULL // Specify Bar Time +) +{ + // + // Validate and Normalize Args ... + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + // Retrieve Bar Time ... + int result = iBarShift( + mSymbol, + mPeriod, + barTime // + ); + + // + return result; +} + +// +// END Bar ... +// + +// +// START Chart Info ... +// + +ENUM_CHART_MODE GetChartMode(long chartId = 0) +{ + return (ENUM_CHART_MODE)ChartGetInteger(chartId, CHART_MODE); +} + +color GetChartUpColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_CHART_UP); +} + +color GetChartDownColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_CHART_DOWN); +} + +color GetChartBullishColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BULL); +} + +color GetChartBearishColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_CANDLE_BEAR); +} + +color GetChartLineColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_CHART_LINE); +} + +color GetChartForeGroundColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_FOREGROUND); +} + +color GetChartBackGroundColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_BACKGROUND); +} + +color GetChartGridColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_GRID); +} + +color GetChartBidLineColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_BID); +} + +color GetChartAskLineColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_ASK); +} + +color GetChartStopColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_STOP_LEVEL); +} + +color GetChartVolumesColor(long chartId = 0) +{ + return (color)ChartGetInteger(chartId, CHART_COLOR_VOLUME); +} + +bool GetChartShowBidLine(long chartId = 0) +{ + return (bool)ChartGetInteger(chartId, CHART_SHOW_BID_LINE); +} + +bool GetChartShowAskLine(long chartId = 0) +{ + return (bool)ChartGetInteger(chartId, CHART_SHOW_ASK_LINE); +} + +bool GetChartShowGrid(long chartId = 0) +{ + return (bool)ChartGetInteger(chartId, CHART_SHOW_GRID); +} + +bool GetChartShowVolumes(long chartId = 0) +{ + return (bool)ChartGetInteger(chartId, CHART_SHOW_VOLUMES); +} + +bool GetChartShowTradeLevels(long chartId = 0) +{ + return (bool)ChartGetInteger(chartId, CHART_SHOW_TRADE_LEVELS); +} + +bool GetChartAutoScroll(long chartId = 0) +{ + return (bool)ChartGetInteger(chartId, CHART_AUTOSCROLL); +} + +bool GetChartQuickNavigation(long chartId = 0) +{ + return (bool)ChartGetInteger(chartId, CHART_QUICK_NAVIGATION); +} + +// +// +// + +bool SetChartMode( + ENUM_CHART_MODE value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_MODE, value); +} + +bool SetChartShowBidLine( + bool value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_SHOW_BID_LINE, value); +} + +bool SetChartShowAskLine( + bool value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_SHOW_ASK_LINE, value); +} + +bool SetChartShowGrid( + bool value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_SHOW_GRID, value); +} + +bool SetChartShowVolumes( + bool value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_SHOW_VOLUMES, value); +} + +bool SetChartShowTradeLevels( + bool value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_SHOW_TRADE_LEVELS, value); +} + +bool SetChartAutoScroll( + bool value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_AUTOSCROLL, value); +} + +bool SetChartQuickNavigation( + bool value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_QUICK_NAVIGATION, value); +} + +bool SetChartForeGroundColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_FOREGROUND, value); +} + +bool SetChartBackGroundColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_BACKGROUND, value); +} + +bool SetChartUpColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_CHART_UP, value); +} + +bool SetChartDownColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_CHART_DOWN, value); +} + +bool SetChartBullishColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_CANDLE_BULL, value); +} + +bool SetChartBearishColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_CANDLE_BEAR, value); +} + +bool SetChartGridColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_GRID, value); +} + +bool SetChartBidLineColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_BID, value); +} + +bool SetChartAskLineColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_ASK, value); +} + +bool SetChartStopColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_STOP_LEVEL, value); +} + +bool SetChartLineColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_CHART_LINE, value); +} + +bool SetChartVolumesColor( + color value, + long chartId = 0 // +) +{ + return ChartSetInteger(chartId, CHART_COLOR_VOLUME, value); +} + +// +// END Chart Info ... +// + +// +// START ATR ... +// + +/** + * Calculate True Range of Specified Bar ... + * + * @param _symbol: string, Symbol ... + * @param _period: ENUM_TIMEFRAMES, period ... + * @param _barIndex: int, Specified Bar Index ... + * @param ignorePC: bool, Ignore Previous Bar ... + * + * @return ( double ) + */ +double GetTrueRange( + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL, + int _barIndex = 0, + bool ignorePC = false // Ignore Previous Close ... +) +{ + // + double result = EMPTY_VALUE; + + // + // Normalize ... + _symbol = NormalizeSymbol(_symbol); + _period = NormalizePeriod(_period); + _barIndex = NormalizeInt(_barIndex, 0); + + // + double _low = iLow(_symbol, _period, _barIndex); + double _high = iHigh(_symbol, _period, _barIndex); + double _pLow = iLow(_symbol, _period, _barIndex + 1); + double _pHigh = iHigh(_symbol, _period, _barIndex + 1); + double _pClose = iClose(_symbol, _period, _barIndex + 1); + + // + double hlDiff = _high - _low; + + // + if (!ignorePC) + { + // + double hpcDiff = MathAbs(_high - _pClose); + double lpcDiff = MathAbs(_high - _pClose); + + // + result = MathMax(hlDiff, hpcDiff); + result = MathMax(result, lpcDiff); + } + else + { + result = hlDiff; + } + + // + return result; +} + +/** + * Calculate ATR ... + * + * @param _symbol: string, Symbol ... + * @param _period: ENUM_TIMEFRAMES, period ... + * @param _barIndex: int, Specified Bar Index ... + * @param _length: int ATR Period ... + * + * @return ( double ) + */ +double GetAverageTrueRange( + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL, + int _barIndex = 0, + int _length = 14 // +) +{ + // + double result = EMPTY_VALUE; + + // + // Normalize ... + _symbol = NormalizeSymbol(_symbol); + _period = NormalizePeriod(_period); + _length = NormalizeInt(_length, 2); + _barIndex = NormalizeInt(_barIndex, 0); + + // + // Collect True Ranges ... + double itr; + double _trs[]; + bool has = false; + int start = _barIndex; + int end = start + _length; + for (int i = start; i < end; i++) + { + // + itr = GetTrueRange( + _symbol, + _period, + _barIndex, + i == end - 1 // Ignore PC ... + ); + has = NotEmptyZero(itr); + if (has) + { + // + Add( + itr, + _trs // + ); + } + } + + // + int count = ArraySize(_trs); + has = HasChild(_trs); + if (!has) + { + return result; + } + + // + result = GetAverage(_trs); + + // + // Cleanup ... + XClean(_trs); + + // + return result; +} + +// +// END ÙŽATR ... +// + +// +// START Linear Regression ... +// + +/** + * Calculate Slope and Intercept for Linear Regression Predictions ... + * + * @param _slope: double, refrence to Hold Calculated Slope ... + * @param _intercept: double, reference to Hold Calculated Intercept ... + * @param xData: double, reference Collection to Provides X-Axis Data for Calculations ... + * @param yData: double, reference Collection to Provides Y-Axis Data for Calculations ... + * + * @return ( int ) + */ +int CalculateSlopeAndIntercept( + double &_slope, + double &_intercept, + double &xData[], + double &yData[] // +) +{ + // + int result = 0; + + // + bool has = false; + + // + _slope = 0; + _intercept = 0; + + // + if (!HasChild(xData) || + !HasChild(yData)) + { + return result; + } + + // + double sumX = 0; + double sumY = 0; + double sumXY = 0; + double sumX2 = 0; + + // + double x = 0; + double y = 0; + int end = MathMin(ArraySize(xData), ArraySize(yData)); + for (int i = 0; i < end; i++) + { + // + double x = xData[i]; + double y = yData[i]; + + // + sumX += x; + sumY += y; + sumXY += x * y; + sumX2 += x * x; + } + + // + int n = end; + double _dividedBy = (n * sumX2 - sumX * sumX); + // if (_dividedBy <= 0 || n <= 0) + // { + // // + // _slope = 0; + // _intercept = 0; + + // // + // result = 0; + // } else { + // // + // _slope = (n * sumXY - sumX * sumY) / _dividedBy; + // _intercept = (sumY - _slope * sumX) / n; + + // // + // result = n; + // } + + // + _slope = (n * sumXY - sumX * sumY) / _dividedBy; + _intercept = (sumY - _slope * sumX) / n; + + // + result = n; + + // + return result; +} + +/** + * Predict Value for Specified X ... + * + * @param _sllope: double, Provided Slope ... + * @param _intercept: double, Provided Intercept ... + * @param _forX: double, Specified XValue ... + * + * @return ( double ) + */ +double PredictValue( + double _slope, + double _intercept, + double _forX // +) +{ + // + double result = 0; + + // + // Validate ... + if (!NotEmpty(_forX) || + !NotEmpty(_slope) || + !NotEmpty(_intercept)) + { + return result; + } + + // + result = (_intercept + (_slope * _forX)); + + // + return result; +} + +// +// END Linear Regression ... +// + +// + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.common.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: XCommonLib +// Description: provide all commonly used functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Libraries/x-saherelm.common.extensions.lib.mq5" +#include "../Libraries/x-saherelm.common.models.lib.mq5" +#include "../Libraries/x-saherelm.x-ohcl.lib.mq5" + +// +// Models ... + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.common.models.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: XModelsLib +// Description: provide all commonly used functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../Libraries/x-saherelm.common.extensions.lib.mq5" + +// +// Use To Parse Symbols for +// Ignore Brokers Additional Suffixes ... +struct XSymbolParser +{ + // + string version; // Temp ... + + // + // Symbol Parsing ... + + // + // Forext ... + + // + bool IsEURUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsUSDJPY(string symbol) + { + // + string symbolIdentifiers[] = { + "USD", + "JPY" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURJPY(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "JPY" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsUSDCHF(string symbol) + { + // + string symbolIdentifiers[] = { + "USD", + "CHF" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURCHF(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "CHF" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsGBPUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "GBP", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURGBP(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "GBP" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsAUDUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "AUD", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURAUD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "AUD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsUSDCAD(string symbol) + { + // + string symbolIdentifiers[] = { + "USD", + "CAD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURCAD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "CAD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsNZDUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "NZD", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsEURNZD(string symbol) + { + // + string symbolIdentifiers[] = { + "EUR", + "NZD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + // Metals ... + + // + bool IsXAUUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "XAU", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + bool IsXAGUSD(string symbol) + { + // + string symbolIdentifiers[] = { + "XAG", + "USD" // + }; + + // + bool result = Contains( + symbolIdentifiers, + symbol // + ); + + // + return result; + } + + // + // Indexes ... + + // + bool IsDowJones(string symbol) + { + // + bool result = Contains( + "DowJones30", + symbol // + ); + + // + return result; + } + + // + // Oil ... + + // + bool IsBrent(string symbol) + { + // + bool result = Contains( + "BRENT", + symbol // + ); + + // + return result; + } + + // + // Symbol Finder ... + string GetEURUSDSymbol() + { + // + string result = NULL; + + // + string symbols[]; + int symbolsCount = GetAllSymbols( + symbols // + ); + if (!IsValidSize(symbolsCount)) + { + return result; + } + + // + for (int i = 0; i < symbolsCount; i++) + { + // + string iSymbol = symbols[i]; + if (IsEURUSD(iSymbol)) + { + // + result = iSymbol; + break; + } + } + + // + return result; + } +}; + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.draw.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Draw Library +// -------------------------------------- +// Name: XDraw +// Description: provides Draw abilities ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Global Definitions: Variables, Properties and etc ... + +// +// Retrieve Chart Size in Pixel ... +struct XSize +{ + long width; + long height; + + // + int x; + int y; + int w; + int h; + + // + int wStep; + int hStep; +}; + +// +// Define a Draw Specifications ... +struct XDrawSpecifications +{ + // + // Props ... + + // + bool draw; // Draw or Not ... + + // + int width; // Draw Witdth ... + color clr; // Draw Color ... + ENUM_LINE_STYLE style; // Draw Style ... + + // + bool back; // in the background + bool fill; // fill object if supported + bool selection; // highlight to move + bool rayRight; // line's continuation to the right + bool hidden; // hidden in the object list + long zOrder; // priority for mouse click + + // + string label; // Label ... + color labelColor; // Label Color ... + double labelAngel; // Label Angle ... + string labelFont; // Label Font ... + int labelFontSize; // Label Font Size ... + ENUM_ANCHOR_POINT labelAnchor; // Label Anchor Point ... + + // + // Constructor ... + XDrawSpecifications() + { + Clean(); + } + + // + // Operator ... + void operator=(const XDrawSpecifications &value) + { + // + clr = value.clr; + draw = value.draw; + width = value.width; + style = value.style; + + // + back = value.back; + hidden = value.hidden; + zOrder = value.zOrder; + rayRight = value.rayRight; + selection = value.selection; + + // + fill = value.fill; + + // + label = value.label; + labelColor = value.labelColor; + labelAngel = value.labelAngel; + labelFont = value.labelFont; + labelFontSize = value.labelFontSize; + labelAnchor = value.labelAnchor; + } + + // + // Functions ... + + // + void Clean() + { + // + draw = false; + width = 1; + clr = CLR_NONE; + style = STYLE_SOLID; + + // + back = false; + hidden = false; + rayRight = false; + selection = false; + fill = false; + + // + zOrder = 0; + + // + label = ""; + labelColor = CLR_NONE; + labelAngel = 0; + labelFont = "Arial"; + labelFontSize = 20; + labelAnchor = ANCHOR_LEFT_UPPER; + + // + ZeroMemory(this); + } + + // + void Label( + string mLabel = "", // Label ... + color mLabelColor = CLR_NONE, // Label Color ... + string mLabelFont = "Arial", // Label Font ... + int mLabelFontSize = 20, // Label Font Size ... + ENUM_ANCHOR_POINT mLabelAnchor = ANCHOR_LEFT_UPPER, // Label Anchor Point ... + double mLabelAngel = 0 // Label Angle ... + ) + { + // + label = mLabel; + labelFont = mLabelFont; + labelColor = mLabelColor; + labelAngel = mLabelAngel; + labelAnchor = mLabelAnchor; + labelFontSize = mLabelFontSize; + } +}; + +// +// Candle Draw Specifications ... +struct XOHCLDrawSpecification +{ + // + // Props ... + XDrawSpecifications openStyle; + XDrawSpecifications highStyle; + XDrawSpecifications closeStyle; + XDrawSpecifications lowStyle; + + // + // Constructors ... + XOHCLDrawSpecification() + { + Clean(); + } + + // + // Operators ... + void operator=(const XOHCLDrawSpecification &value) + { + // + lowStyle = value.lowStyle; + openStyle = value.openStyle; + highStyle = value.highStyle; + closeStyle = value.closeStyle; + } + + // + // Functions ... + + // + void Clean() + { + // + lowStyle.Clean(); + openStyle.Clean(); + highStyle.Clean(); + closeStyle.Clean(); + + // + ZeroMemory(this); + } + + // + void Default() + { + // + // Open ... + openStyle.width = 1; + openStyle.draw = true; + openStyle.clr = clrLime; + openStyle.style = STYLE_SOLID; + openStyle.Label( + "O", + openStyle.clr); + + // + // High ... + highStyle.width = 1; + highStyle.draw = true; + highStyle.clr = clrAqua; + highStyle.style = STYLE_SOLID; + highStyle.Label( + "H", + highStyle.clr); + + // + // Close ... + closeStyle.width = 1; + closeStyle.draw = true; + closeStyle.clr = clrRed; + closeStyle.style = STYLE_SOLID; + closeStyle.Label( + "C", + closeStyle.clr); + + // + // Low ... + lowStyle.width = 1; + lowStyle.draw = true; + lowStyle.clr = clrMagenta; + lowStyle.style = STYLE_SOLID; + lowStyle.Label( + "L", + lowStyle.clr); + } + + // + void Width(int value) + { + // + lowStyle.width = value; + openStyle.width = value; + highStyle.width = value; + closeStyle.width = value; + } + + // + void Style(ENUM_LINE_STYLE value) + { + // + lowStyle.style = value; + openStyle.style = value; + highStyle.style = value; + closeStyle.style = value; + } + + // + void Color(color value) + { + // + lowStyle.clr = value; + openStyle.clr = value; + highStyle.clr = value; + closeStyle.clr = value; + } + + // + void RayRight(bool value) + { + // + lowStyle.rayRight = value; + openStyle.rayRight = value; + highStyle.rayRight = value; + closeStyle.rayRight = value; + } + + // + void Draw(bool value) + { + // + lowStyle.draw = value; + openStyle.draw = value; + highStyle.draw = value; + closeStyle.draw = value; + } + + // + void Back(bool value) + { + // + lowStyle.back = value; + openStyle.back = value; + highStyle.back = value; + closeStyle.back = value; + } + + // + void Fill(bool value) + { + // + lowStyle.fill = value; + openStyle.fill = value; + highStyle.fill = value; + closeStyle.fill = value; + } + + // + void Label(string value) + { + // + lowStyle.Label(value); + openStyle.Label(value); + highStyle.Label(value); + closeStyle.Label(value); + } + + // + void SetLabelPrefix(string value) + { + // + lowStyle.label = value + " " + lowStyle.label; + openStyle.label = value + " " + openStyle.label; + highStyle.label = value + " " + highStyle.label; + closeStyle.label = value + " " + closeStyle.label; + } +}; + +// +string drawPrefix = "X-OBJ"; + +// +// Common Draw Functions ... + +// +// remove drawn objects ... +void RemoveDraws( + string tag = NULL, + long chartId = -1, + int subWindow = -1 // +) +{ + // + // Normalize Args ... + // + if (tag == NULL) + { + tag = drawPrefix; + } + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, tag) >= 0) + { + ObjectDelete(chartId, on); + } + } + + // + // Redraw Chart ... + ChartRedraw(); +} + +// +bool RemoveDraw( + string name, + long chartId = -1, + int subWindow = -1 // +) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + string objName = ""; + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + if (StringFind(on, name) >= 0) + { + // + objName = on; + break; + } + } + + // + if (StringLen(objName) > 0) + { + result = ObjectDelete(chartId, objName); + } + + // + return result; +} + +// +// Deselect All Draws ... +void DeselectAllDraws() +{ + // + int objs = ObjectsTotal(ChartID(), 0); + for (int o = 0; o < objs; o++) + { + ObjectSetInteger(ChartID(), ObjectName(ChartID(), o, 0), OBJPROP_SELECTED, false); + } + + // + ChartRedraw(); +} + +// +// Check Object Exists ... +bool IsDrawExists( + string name, + long chartId = -1, + int subWindow = -1 // +) +{ + // + bool result = false; + + // + if (chartId == -1) + { + chartId = 0; + } + + // + if (subWindow == -1) + { + subWindow = 0; + } + + // + for (int iObj = ObjectsTotal(chartId, subWindow) - 1; iObj >= 0; iObj--) + { + // + string on = ObjectName(chartId, iObj, subWindow); + result = StringFind(on, name) >= 0; + if (result) + { + break; + } + } + + // + return result; +} + +// +// Find Specific Object Name ... +string FindObjectName( + string suggest, + long chartId = 0, + int subWindow = 0 // +) +{ + // + string result = NULL; + + // + int objectsCount = ObjectsTotal(chartId, subWindow); + if (objectsCount <= 0) + { + return result; + } + + // + for (int i = objectsCount - 1; i >= 0; i--) + { + // + string iObjectName = ObjectName(chartId, i, subWindow); + bool isExists = StringFind(iObjectName, suggest) >= 0; + if (isExists) + { + // + result = iObjectName; + break; + } + } + + // + return result; +} + +// +// Regular Draws ... + +// +// Arrow Functions ... + +// +// Draw an Arrow Object on Chart ... +bool DrawArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // arrow name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const uchar arrowCode = 252, // arrow code + const ENUM_ARROW_ANCHOR anchor = ANCHOR_BOTTOM, // anchor point position + const color clr = clrAqua, // arrow color + const ENUM_LINE_STYLE style = STYLE_SOLID, // border line style + const int width = 3, // arrow size + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // Order Object ... +) +{ + // + bool result = false; + + // + // set anchor point coordinates if they are not set ... + ChangeArrowEmptyPoint(time, price); + + // + // reset the error value ... + ResetLastError(); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create an arrow ... + result = ObjectCreate(chartID, objName, OBJ_ARROW, subWindow, time, price); + if (!result) + { + return result; + } + + // + // set the arrow code ... + ObjectSetInteger(chartID, objName, OBJPROP_ARROWCODE, arrowCode); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set the arrow color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set the border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set the arrow's size ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the arrow by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is false by default, if you want making it possible to highlight and move the object + // change it to true ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move the anchor point of Arrow ... +bool MoveArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // move the anchor point ... + result = ObjectMove(chartID, objName, 0, time, price); + + // + return result; +} + +// +// Delete an arrow ... +bool DeleteArrow( + const long chartID = 0, // chart's ID + const string name = "Arrow" // arrow name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete an arrow ... + result = !ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Change the arrow code ... +bool ArrowCodeChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const uchar code = 252 // arrow code +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change the arrow code ... + result = ObjectSetInteger(chartID, objName, OBJPROP_ARROWCODE, code); + + // + return result; +} + +// +// Change anchor type ... +bool ArrowAnchorChange( + const long chartID = 0, // chart's ID + const string name = "Arrow", // object name + const ENUM_ARROW_ANCHOR anchor = ANCHOR_TOP // anchor type +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change anchor type ... + result = !ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + return result; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeArrowEmptyPoint( + datetime &time, + double &price // +) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} + +// +// Horizontal Line Functions ... + +// +// Create, Draw the horizontal line ... +bool DrawHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + const int subWindow = 0, // subwindow index + double price = 0, // line price + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // if the price is not set, set it at the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a horizontal line ... + result = ObjectCreate(chartID, objName, OBJ_HLINE, subWindow, 0, price); + if (!result) + { + return result; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move horizontal line ... +bool MoveHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine", // line name + double price = 0 // line price +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if the line price is not set, move it to the current Bid price level ... + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // move a horizontal line ... + result = ObjectMove(chartID, objName, 0, 0, price); + + // + return result; +} + +// +// Delete a horizontal line ... +bool DeleteHorizontalLine( + const long chartID = 0, // chart's ID + const string name = "HLine" // line name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete a horizontal line ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Vertical Line Functions ... + +// +// Create the vertical line ... +bool DrawVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + const int subWindow = 0, // subwindow index + datetime time = 0, // line time + const color clr = clrRed, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // if the line time is not set, draw it via the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a vertical line ... + result = ObjectCreate(chartID, objName, OBJ_VLINE, subWindow, time, 0); + if (!result) + { + return result; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move the vertical line ... +bool MoveVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine", // line name + datetime time = 0 // line time +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if line time is not set, move the line to the last bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // move the vertical line ... + result = ObjectMove(chartID, objName, 0, time, 0); + + // + return result; +} + +// +// Delete the vertical line ... +bool DeleteVerticalLine( + const long chartID = 0, // chart's ID + const string name = "VLine" // line name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the vertical line ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Rectangle Functions ... + +// +// Create rectangle by the given coordinates ... +bool DrawRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // down first point time + double price1 = 0, // down first point price + datetime time2 = 0, // up second point time + double price2 = 0, // up second point price + const color clr = clrRed, // rectangle color + const ENUM_LINE_STYLE style = STYLE_SOLID, // style of rectangle lines + const int width = 1, // width of rectangle lines + const bool fill = false, // filling rectangle with color + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Set anchor points' coordinates if they are not set ... + ChangeRectangleEmptyPoints(time1, price1, time2, price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create a rectangle by the given coordinates ... + result = ObjectCreate( + chartID, + objName, + OBJ_RECTANGLE, + subWindow, + time1, + price1, + time2, + price2 // + ); + if (!result) + { + return result; + } + + // + // Set rectangle color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // Set the style of rectangle lines + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // Set width of the rectangle lines ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // Enable (true) or disable (false) the mode of filling the rectangle ... + ObjectSetInteger(chartID, objName, OBJPROP_FILL, fill); + + // + // Display in the foreground (false) or background (true) ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // Enable (true) or disable (false) the mode of highlighting the rectangle for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + + // + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // Hide (true) or display (false) graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // Set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // Successful execution + return result; +} + +// +// Move the rectangle anchor point ...s +bool RectanglePointChange( + const long chartID = 0, // chart's ID + const string name = "Rectangle", // rectangle name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // Move the anchor point ... + result = ObjectMove(chartID, objName, pointIndex, time, price); + + // + return result; +} + +// +// Delete the rectangle ... +bool DeleteRectangle( + const long chartID = 0, // chart's ID + const string name = "Rectangle" // rectangle name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check the values of rectangle's anchor points and set default +// values for empty ones +void ChangeRectangleEmptyPoints( + datetime &time1, double &price1, + datetime &time2, double &price2 // +) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, move it 300 points lower than the first one ... + if (!price2) + { + price2 = price1 - 300 * SymbolInfoDouble(Symbol(), SYMBOL_POINT); + } +} + +// +// RectangleLabel Functions ... + +// +// Create Rectangle Label Object ... +bool DrawRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // width + const int height = 18, // height + const color bgColor = clrWhiteSmoke, // background color + const ENUM_BORDER_TYPE border = BORDER_SUNKEN, // border type + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const color clr = clrRed, // flat border color (Flat) + const ENUM_LINE_STYLE style = STYLE_SOLID, // flat border style + const int lineWidth = 1, // flat border width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a rectangle label + result = ObjectCreate(chartID, objName, OBJ_RECTANGLE_LABEL, subWindow, 0, 0); + if (!result) + { + return result; + } + + // + // set label coordinates ... + ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + // set label size ... + ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + // set background color ... + ObjectSetInteger(chartID, objName, OBJPROP_BGCOLOR, bgColor); + + // + // set border type ... + ObjectSetInteger(chartID, objName, OBJPROP_BORDER_TYPE, border); + + // + // set the chart's corner, relative to which point coordinates are defined ... + ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + // set flat border color (in Flat mode) ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set flat border line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set flat border width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, lineWidth); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the label by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move Rectangle Label .. +bool MoveRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // move the rectangle label ... + result = ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + return result; +} + +// +// Delete the rectangle label ... +bool DeleteRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel" // label name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the label ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Change Rectangle Label Size ... +bool ChangeSizeRectangleLabel( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const int width = 50, // label width + const int height = 18 // label height +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change label size ... + result = ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + return result; +} + +// +// Change rectangle label border type ... +bool RectLabelChangeBorderType( + const long chartID = 0, // chart's ID + const string name = "RectLabel", // label name + const ENUM_BORDER_TYPE border = BORDER_SUNKEN // border type +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change border type ... + result = ObjectSetInteger(chartID, objName, OBJPROP_BORDER_TYPE, border); + + // + return result; +} + +// +// TrendLine Funcions ... + +// +// Create a trend line by the given coordinates ... +bool DrawTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrYellow, // line color + const ENUM_LINE_STYLE style = STYLE_SOLID, // line style + const int width = 1, // line width + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool rayRight = false, // line's continuation to the right + const bool hidden = false, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor points' coordinates if they are not set ... + ChangeTrendLineEmptyPoints( + time1, + price1, + time2, + price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create a trend line by the given coordinates ... + result = ObjectCreate(chartID, objName, OBJ_TREND, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // set line color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line display style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the line by mouse + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the line's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move trend line anchor point ... | +bool ChangeTrendLinePoint( + const long chartID = 0, // chart's ID + const string name = "TrendLine", // line name + const int pointindex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // move trend line's anchor point ... + result = ObjectMove(chartID, objName, pointindex, time, price); + + // + return result; +} + +// +// The function deletes the trend line from the chart ... +bool DeleteTrendLine( + const long chartID = 0, // chart's ID + const string name = "TrendLine" // line name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete a trend line ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check the values of trend line's anchor points and set default ... +// values for empty ones ... +void ChangeTrendLineEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2 // +) +{ + // + // if the first point's time is not set, it will be on the current bar ... + if (!time1) + { + time1 = TimeCurrent(); + } + + // + // if the first point's price is not set, it will have Bid value ... + if (!price1) + { + price1 = SymbolInfoDouble(Symbol(), SYMBOL_BID); + } + + // + // if the second point's time is not set, it is located 9 bars left from the second one ... + if (!time2) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time1, 10, temp); + + // + // set the second point 9 bars left from the first one ... + time2 = temp[0]; + } + + // + // if the second point's price is not set, it is equal to the first point's one ... + if (!price2) + { + price2 = price1; + } +} + +// +// Text Functions ... + +// +// Create and Draw a Text Object ... +bool DrawText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const int subWindow = 0, // subwindow index + datetime time = 0, // anchor point time + double price = 0, // anchor point price + const string text = "Text", // the text itself + const string font = "Arial", // font + const int fontSize = 10, // font size + const color clr = clrRed, // color + const double angle = 0.0, // text slope + const ENUM_ANCHOR_POINT anchor = ANCHOR_CENTER, // anchor type + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor point coordinates if they are not set ... + ChangeTextEmptyPoint(time, price); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // create Text object + result = ObjectCreate(chartID, objName, OBJ_TEXT, subWindow, time, price); + if (!result) + { + return result; + } + + // + // set the text ... + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set text font ... + ObjectSetString(chartID, objName, OBJPROP_FONT, font); + + // + // set font size ... + ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE, fontSize); + + // + // set the slope angle of the text ... + ObjectSetDouble(chartID, objName, OBJPROP_ANGLE, angle); + + // + // set anchor type ... + ObjectSetInteger(chartID, objName, OBJPROP_ANCHOR, anchor); + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving the object by mouse ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Move the anchor point ... +bool MoveText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // + // if point position is not set, move it to the current bar having Bid price + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // move the anchor point ... + result = ObjectMove(chartID, objName, 0, time, price); + + // + return result; +} + +// +// Change the object text ... +bool ChangeText( + const long chartID = 0, // chart's ID + const string name = "Text", // object name + const string text = "Text" // text +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change object text ... + result = ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Delete Text object ... +bool DeleteText( + const long chartID = 0, // chart's ID + const string name = "Text" // object name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the object ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check anchor point values and set default values +// for empty ones ... +void ChangeTextEmptyPoint( + datetime &time, + double &price // +) +{ + // + // if the point's time is not set, it will be on the current bar ... + if (!time) + { + time = TimeCurrent(); + } + + // + // if the point's price is not set, it will have Bid value ... + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } +} + +// +// Fibonacchi Functions ... + +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawFibonacci( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrRed, // object color + const ENUM_LINE_STYLE style = STYLE_SOLID, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + result = ObjectCreate(chartID, objName, OBJ_FIBO, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution ... + return result; +} + +// +// Create Fibonacci Retracement by the given coordinates ... +bool DrawCustomFibonacci( + // + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + // + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int subWindow = 0, // subwindow index + datetime time1 = 0, // first point time + double price1 = 0, // first point price + datetime time2 = 0, // second point time + double price2 = 0, // second point price + const color clr = clrAqua, // object color + const ENUM_LINE_STYLE style = STYLE_DOT, // object line style + const int width = 1, // object line width + const bool back = false, // in the background + const bool selection = true, // highlight to move + const bool rayRight = false, // object's continuation to the right + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // set anchor points' coordinates if they are not set ... + ChangeFibonacciEmptyPoints(time1, price1, time2, price2); + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // Create Fibonacci Retracement by the given coordinates ... + result = ObjectCreate(chartID, name, OBJ_FIBO, subWindow, time1, price1, time2, price2); + if (!result) + { + return result; + } + + // + // set color ... + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set line style ... + ObjectSetInteger(chartID, objName, OBJPROP_STYLE, style); + + // + // set line width ... + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true ... + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of highlighting the channel for moving + // when creating a graphical object using ObjectCreate function, the object cannot be + // highlighted and moved by default. Inside this method, selection parameter + // is true by default making it possible to highlight and move the object ... + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, true); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // enable true or disable false the mode of continuation of the object's display to the right ... + ObjectSetInteger(chartID, objName, OBJPROP_RAY_RIGHT, rayRight); + + // + // hide true or display false graphical object name in the object list ... + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart ... + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // Change Levels Of Fibonacci ... + result = FibonacciLevelsSet( + levels, + values, + colors, + styles, + widths, + descriptions, + chartID, + objName); + + // + // successful execution ... + return result; +} + +// +// Set number of levels and their parameters ... +bool FibonacciLevelsSet( + int levels, // number of level lines + double &values[], // values of level lines + color &colors[], // color of level lines + ENUM_LINE_STYLE &styles[], // style of level lines + int &widths[], // width of level lines + string &descriptions[], // level Descriptions + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + bool result = false; + + // + // check array sizes ... + result = levels == ArraySize(colors) && + levels == ArraySize(styles) && + levels == ArraySize(widths) && + levels == ArraySize(widths); + if (!result) + { + return result; + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // set the number of levels ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELS, levels); + + // + // set the properties of levels in the loop ... + for (int i = 0; i < levels; i++) + { + // + // level value ... + ObjectSetDouble(chartID, objName, OBJPROP_LEVELVALUE, i, values[i]); + + // + // level color ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELCOLOR, i, colors[i]); + + // + // level style ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELSTYLE, i, styles[i]); + + // + // level width ... + ObjectSetInteger(chartID, objName, OBJPROP_LEVELWIDTH, i, widths[i]); + + // + // level description ... + // ObjectSetString(chartID, name, OBJPROP_LEVELTEXT, i, DoubleToString(100 * values[i], 1)); + ObjectSetString(chartID, objName, OBJPROP_LEVELTEXT, i, descriptions[i]); + } + + // + // successful execution ... + return result; +} + +// +// Move Fibonacci Retracement anchor point ... +bool FibonacciPointChange( + const long chartID = 0, // chart's ID + const string name = "Fibonacci", // object name + const int pointIndex = 0, // anchor point index + datetime time = 0, // anchor point time coordinate + double price = 0 // anchor point price coordinate +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if point position is not set, move it to the current bar having Bid price ... + if (!time) + { + time = TimeCurrent(); + } + + // + if (!price) + { + price = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // move the anchor point ... + result = ObjectMove(chartID, objName, pointIndex, time, price); + + // + return result; +} + +// +// Delete Fibonacci Retracement ... +bool DeleteFibonachi( + const long chartID = 0, // chart's ID + const string name = "Fibonacci" // object name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the object ... + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Check the values of Fibonacci Retracement anchor points and set +// default values for empty ones ... +void ChangeFibonacciEmptyPoints( + datetime &time1, + double &price1, + datetime &time2, + double &price2 // +) +{ + // + // if the second point's time is not set, it will be on the current bar ... + if (!time2) + { + time2 = TimeCurrent(); + } + + // + // if the second point's price is not set, it will have Bid value ... + if (!price2) + { + price2 = SymbolInfoDouble(_Symbol, SYMBOL_BID); + } + + // + // if the first point's time is not set, it is located 9 bars left from the second one ... + if (!time1) + { + // + // array for receiving the open time of the last 10 bars ... + datetime temp[10]; + CopyTime(Symbol(), Period(), time2, 10, temp); + + // + // set the first point 9 bars left from the second one ... + time1 = temp[0]; + } + + // + // if the first point's price is not set, move it 200 points below the second one ... + if (!price1) + { + price1 = price2 - 200 * SymbolInfoDouble(_Symbol, SYMBOL_POINT); + } +} + +// +// Event Functions ... + +// +// Create an Event ... +bool EventCreate( + const long chartID = 0, // chart's ID + const string name = "Event", // object name + const int subWindow = 0, // subwindow index + const string text = "Content", // event text + datetime time = 0, // anchor point time + const color clr = clrRed, // color + const int width = 1, // point width when highlighted + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + if (!time) + { + time = TimeCurrent(); + } + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectCreate(chartID, objName, OBJ_EVENT, subWindow, time, 0); + if (!result) + { + return result; + } + + // + // set event text + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set color + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set anchor point width if the object is highlighted + ObjectSetInteger(chartID, objName, OBJPROP_WIDTH, width); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // enable true or disable false the mode of moving event by mouse + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + // successful execution + return result; +} + +// +// Change Event object text +bool EventTextChange( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + const string text = "Content" // text +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change object text + result = ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Move Event object +bool EventMove( + const long chartID = 0, // chart's ID + const string name = "Event", // event name + datetime time = 0 // time +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // if time is not set, move event to the last bar + if (!time) + { + time = TimeCurrent(); + } + + // + // move the object + result = ObjectMove(chartID, objName, 0, time, 0); + + // + return result; +} + +// +// Delete Event object +bool EventDelete( + const long chartID = 0, // chart's ID + const string name = "Event" // event name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the object + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Button Functions ... + +// +// Create the button ... +bool ButtonCreate( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int subWindow = 0, // subwindow index + const int x = 0, // X coordinate + const int y = 0, // Y coordinate + const int width = 50, // button width + const int height = 15, // button height + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER, // chart corner for anchoring + const string text = "Button", // text + const string font = "Arial", // font + const int fontSize = 8, // font size + const color clr = clrBlack, // text color + const color bgColor = clrLightGray, // background color + const color borderColor = clrNONE, // border color + const bool state = false, // pressed/released + const bool back = false, // in the background + const bool selection = false, // highlight to move + const bool hidden = true, // hidden in the object list + const long zOrder = 0 // priority for mouse click +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // create the button + result = ObjectCreate(chartID, objName, OBJ_BUTTON, subWindow, 0, 0); + if (!result) + { + return result; + } + + // + // set button coordinates + ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + // set button size + ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + // set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + // set the text + ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + // set text font + ObjectSetString(chartID, objName, OBJPROP_FONT, font); + + // + // set font size + ObjectSetInteger(chartID, objName, OBJPROP_FONTSIZE, fontSize); + + // + // set text color + ObjectSetInteger(chartID, objName, OBJPROP_COLOR, clr); + + // + // set background color + ObjectSetInteger(chartID, objName, OBJPROP_BGCOLOR, bgColor); + + // + // set border color + ObjectSetInteger(chartID, objName, OBJPROP_BORDER_COLOR, borderColor); + + // + // display in the foreground false or background true + ObjectSetInteger(chartID, objName, OBJPROP_BACK, back); + + // + // set button state + ObjectSetInteger(chartID, objName, OBJPROP_STATE, state); + + // + // enable true or disable false the mode of moving the button by mouse + ObjectSetInteger(chartID, objName, OBJPROP_SELECTABLE, selection); + ObjectSetInteger(chartID, objName, OBJPROP_SELECTED, selection); + + // + // hide true or display false graphical object name in the object list + ObjectSetInteger(chartID, objName, OBJPROP_HIDDEN, hidden); + + // + // set the priority for receiving the event of a mouse click in the chart + ObjectSetInteger(chartID, objName, OBJPROP_ZORDER, zOrder); + + // + return result; +} + +// +// Move the button ... +bool ButtonMove( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int x = 0, // X coordinate + const int y = 0 // Y coordinate +) +{ + // + bool result = false; + + // + // move the button + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_XDISTANCE, x); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YDISTANCE, y); + + // + return result; +} + +// +// Change button size ... +bool ButtonChangeSize( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const int width = 50, // button width + const int height = 18 // button height +) +{ + // + bool result = false; + + // + // change the button size + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_XSIZE, width); + if (!result) + { + return result; + } + + // + result = ObjectSetInteger(chartID, objName, OBJPROP_YSIZE, height); + + // + return result; +} + +// +// Change corner of the chart for binding the button ... +bool ButtonChangeCorner( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const ENUM_BASE_CORNER corner = CORNER_LEFT_UPPER // chart corner for anchoring +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change anchor corner + result = ObjectSetInteger(chartID, objName, OBJPROP_CORNER, corner); + + // + return result; +} + +// +// Change button text ... +bool ButtonTextChange( + const long chartID = 0, // chart's ID + const string name = "Button", // button name + const string text = "Text" // text +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // change object text + result = ObjectSetString(chartID, objName, OBJPROP_TEXT, text); + + // + return result; +} + +// +// Delete the button ... +bool ButtonDelete( + const long chartID = 0, // chart's ID + const string name = "Button" // button name +) +{ + // + bool result = false; + + // + // Normalize Name ... + string objName = drawPrefix + "_" + name; + + // + // delete the button + result = ObjectDelete(chartID, objName); + + // + return result; +} + +// +// Chart Style Drawers ... + +// +// Apply Styles On Chart ... +void ApplyChartStyle( + long mChartId = -1, // chart's ID + ENUM_CHART_MODE mMode = CHART_CANDLES, // chart's mMode + bool mShowBidLine = true, // show bid line + bool mShowAskLine = true, // show ask line + bool mShowGrid = false, // show grids on chart + bool mShowVolumes = false, // show volumes + bool mShowTradeLevels = true, // Displaying trade levels in the chart (levels of open positions, Stop Loss, Take Profit and pending orders) + bool mAutoScroll = true, // chart autoscroll + bool mQuickNavigation = true, // chart quick navigation state + color mForeGroundColor = clrWhite, // chart's foreground color + color mBackGroundColor = clrBlack, // chart's background color + color mUpColor = clrGreen, // Up Color + color mDownColor = clrRed, // Down Color + color mBullishColor = clrGreen, // Bullish color + color mBearishColor = clrRed, // Bearish color + color mGridColor = clrGray, // grid color + color mBidLineColor = clrGray, // bid line color + color mAskLineColor = clrRed, // ask line color + color mLineColor = clrLime, // line mMode and doji candlestick color + color mStopColor = clrGold, // Color of stop order levels (Stop Loss and Take Profit) + color mVolumesColor = clrGreen // volumes color +) +{ + // + // Validate Args ... + if (mChartId == -1) + { + mChartId = 0; + } + + // + ChartSetInteger(mChartId, CHART_MODE, mMode); + ChartSetInteger(mChartId, CHART_SHOW_BID_LINE, mShowBidLine); + ChartSetInteger(mChartId, CHART_SHOW_ASK_LINE, mShowAskLine); + ChartSetInteger(mChartId, CHART_SHOW_GRID, mShowGrid); + ChartSetInteger(mChartId, CHART_SHOW_VOLUMES, mShowVolumes); + ChartSetInteger(mChartId, CHART_SHOW_TRADE_LEVELS, mShowTradeLevels); + ChartSetInteger(mChartId, CHART_AUTOSCROLL, mAutoScroll); + ChartSetInteger(mChartId, CHART_QUICK_NAVIGATION, mQuickNavigation); + ChartSetInteger(mChartId, CHART_COLOR_FOREGROUND, mForeGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_BACKGROUND, mBackGroundColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_UP, mUpColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_DOWN, mDownColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BULL, mBullishColor); + ChartSetInteger(mChartId, CHART_COLOR_CANDLE_BEAR, mBearishColor); + ChartSetInteger(mChartId, CHART_COLOR_GRID, mGridColor); + ChartSetInteger(mChartId, CHART_COLOR_BID, mBidLineColor); + ChartSetInteger(mChartId, CHART_COLOR_ASK, mAskLineColor); + ChartSetInteger(mChartId, CHART_COLOR_STOP_LEVEL, mStopColor); + ChartSetInteger(mChartId, CHART_COLOR_CHART_LINE, mLineColor); + ChartSetInteger(mChartId, CHART_COLOR_VOLUME, mVolumesColor); +} + +// +// Tools ... + +// +// Retrieve Chart Size ... +bool GetChartSize( + XSize &result, // Holds Result ... + long chartID = 0 // Specified Chart ID ... +) +{ + // + bool mResult = false; + + // + mResult = ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0, result.width); + if (!mResult) + { + return mResult; + } + + // + mResult = ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0, result.height); + + // + return mResult; +} + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.x-enums.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: XEnumsLib +// Description: provide all commonly used functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// START Price Type ... +// + +// +// Availables Price Types ... +enum ENUM_X_PRICE +{ + X_PRICE_NONE, // None + X_PRICE_HIGH, // High + X_PRICE_OPEN, // Open + X_PRICE_CLOSE, // Close + X_PRICE_LOW, // Low + X_PRICE_UP, // Body Up + X_PRICE_DOWN, // Body Down + X_PRICE_MEDIAN, // Median + X_PRICE_BODY_MEDIAN, // Body Median + X_PRICE_TYPICAL, // Typical + X_PRICE_WEIGHTED // Weighted +}; + +// +// Extensions ... + +/** + * Validate ... + * + * @param value: ENUM_X_PRICE member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_PRICE value) +{ + // + bool result = false; + + // + result = + value != NULL && + value != X_PRICE_NONE; + + // + return result; +} +bool IsXValid(ENUM_X_PRICE value) +{ + return IsValid(value); +} + +/** + * Converts Series Mode to ENUM_X_PRICE ... + * + * @param value: ENUM_SERIESMODE member ... + * + * @return ( ENUM_X_PRICE ) + */ +ENUM_X_PRICE ToXPrice(ENUM_SERIESMODE value) +{ + // + ENUM_X_PRICE result = X_PRICE_CLOSE; + + // + switch (value) + { + // + // High ... + case MODE_HIGH: + result = X_PRICE_HIGH; + break; + + // + // Open ... + case MODE_OPEN: + result = X_PRICE_OPEN; + break; + + // + // Low ... + case MODE_LOW: + result = X_PRICE_LOW; + break; + + // + // Close ... + // Default ... + case MODE_CLOSE: + default: + result = X_PRICE_CLOSE; + break; + } + + // + return result; +} + +/** + * Converts Applied Price to ENUM_X_PRICE ... + * + * @param value: ENUM_APPLIED_PRICE member ... + * + * @return ( ENUM_X_PRICE ) + */ +ENUM_X_PRICE ToXPrice(ENUM_APPLIED_PRICE value) +{ + // + ENUM_X_PRICE result = X_PRICE_NONE; + + // + switch (value) + { + // + case PRICE_HIGH: + result = X_PRICE_HIGH; + break; + + // + case PRICE_OPEN: + result = X_PRICE_OPEN; + break; + + // + case PRICE_CLOSE: + result = X_PRICE_CLOSE; + break; + + // + case PRICE_LOW: + result = X_PRICE_LOW; + break; + + // + case PRICE_MEDIAN: + result = X_PRICE_MEDIAN; + break; + + // + case PRICE_TYPICAL: + result = X_PRICE_TYPICAL; + break; + + // + case PRICE_WEIGHTED: + result = X_PRICE_WEIGHTED; + break; + } + + // + return result; +} + +/** + * Converts Price Type to Applied Price ... + * + * @param value: ENUM_X_PRICE member ... + * + * @return ( ENUM_APPLIED_PRICE ) + */ +ENUM_APPLIED_PRICE ToAppliedPrice(ENUM_X_PRICE value) +{ + // + // Default ... + ENUM_APPLIED_PRICE result = PRICE_CLOSE; + + // + if (!IsValid(value) || + value == X_PRICE_UP || + value == X_PRICE_DOWN || + value == X_PRICE_BODY_MEDIAN) + { + return result; + } + + // + switch (value) + { + // + case X_PRICE_HIGH: + result = PRICE_HIGH; + break; + + // + case X_PRICE_OPEN: + result = PRICE_OPEN; + break; + + // + case X_PRICE_CLOSE: + result = PRICE_CLOSE; + break; + + // + case X_PRICE_LOW: + result = PRICE_LOW; + break; + + // + case X_PRICE_MEDIAN: + result = PRICE_MEDIAN; + break; + + // + case X_PRICE_TYPICAL: + result = PRICE_TYPICAL; + break; + + // + case X_PRICE_WEIGHTED: + result = PRICE_WEIGHTED; + break; + } + + // + return result; +} +ENUM_APPLIED_PRICE ToXAppliedPrice(ENUM_X_PRICE value) +{ + return ToAppliedPrice(value); +} + +/** + * Converts To String ... + * + * @param value: ENUM_X_PRICE member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_PRICE value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_PRICE_NONE: + result = "None"; + break; + + // + case X_PRICE_HIGH: + result = "High"; + break; + + // + case X_PRICE_OPEN: + result = "Open"; + break; + + // + case X_PRICE_CLOSE: + result = "Close"; + break; + + // + case X_PRICE_LOW: + result = "Low"; + break; + + // + case X_PRICE_UP: + result = "Body Up"; + break; + + // + case X_PRICE_DOWN: + result = "Body Down"; + break; + + // + case X_PRICE_MEDIAN: + result = "Median"; + break; + + // + case X_PRICE_BODY_MEDIAN: + result = "Body Median"; + break; + + // + case X_PRICE_TYPICAL: + result = "Typical"; + break; + + // + case X_PRICE_WEIGHTED: + result = "Weighted"; + break; + } + + // + return result; +} +string ToXString(ENUM_X_PRICE value) +{ + return ToString(value); +} + +// +// END Price Type ... +// + +// +// START Boundary Price Type ... +// + +// +// Available Boundary Price Types ... +enum ENUM_X_BOUNDARY_PRICE +{ + X_BOUNDARY_PRICE_NONE, // None + X_BOUNDARY_PRICE_UP_DOWN, // Up/Down + X_BOUNDARY_PRICE_HIGH_LOW, // High/Low +}; + +/** + * Validate ... + * + * @param value: ENUM_X_BOUNDARY_PRICE member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_BOUNDARY_PRICE value) +{ + // + bool result = false; + + // + result = + value != NULL && + value != X_BOUNDARY_PRICE_NONE; + + // + return result; +} +bool IsXValid(ENUM_X_BOUNDARY_PRICE value) +{ + return IsValid(value); +} +bool IsSpecifiedValid(ENUM_X_BOUNDARY_PRICE value) +{ + return IsValid(value); +} + +/** + * Converts To String ... + * + * @param value: ENUM_X_BOUNDARY_PRICE member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_BOUNDARY_PRICE value) +{ + // + string result = NULL; + + // + if (!IsValid(value)) + { + value = X_BOUNDARY_PRICE_NONE; + } + + // + result = EnumToString(value); + + // + return result; +} +string ToXString(ENUM_X_BOUNDARY_PRICE value) +{ + return ToString(value); +} + +// +// END Boundary Price Type ... +// + +// +// START Direction ... +// + +// +// Directions ... +enum ENUM_X_DIRECTION +{ + X_DIRECTION_ALL, // All + X_DIRECTION_NONE, // None + X_DIRECTION_BULLISH, // Bullish + X_DIRECTION_BEARISH, // Bearish +}; + +// +// Extensions ... + +/** + * Validate ... + * + * @param value: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = + value != NULL && + value != X_DIRECTION_NONE; + + // + return result; +} +bool IsXValid(ENUM_X_DIRECTION value) +{ + return IsValid(value); +} +bool IsSpecifiedValid(ENUM_X_DIRECTION value) +{ + return IsValid(value); +} + +/** + * Validate value Has Specified Direction ... + * + * @param value: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ +bool HasDirection(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = IsValid(value) && + value != X_DIRECTION_ALL; + + // + return result; +} + +/** + * Check a Direction is Bullish or not ... + * + * @param value: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ +bool IsBullish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BULLISH; + + // + return result; +} +bool IsXBullish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BULLISH; + + // + return result; +} +bool IsSpecifiedBullish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BULLISH; + + // + return result; +} + +/** + * Check a Direction is Bearish or not ... + * + * @param value: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ +bool IsBearish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BEARISH; + + // + return result; +} +bool IsXBearish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BEARISH; + + // + return result; +} +bool IsSpecifiedBearish(ENUM_X_DIRECTION value) +{ + // + bool result = false; + + // + result = value == X_DIRECTION_BEARISH; + + // + return result; +} + +/** + * Converts Specified Direction to Opposit ... + * + * @param value: ENUM_X_DIRECTION member ... + * + * @return ( ENUM_X_DIRECTION ) + */ +ENUM_X_DIRECTION Opposit(ENUM_X_DIRECTION value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + if (!HasDirection(value)) + { + return result; + } + + // + result = + IsBullish(value) + ? X_DIRECTION_BEARISH + : X_DIRECTION_BULLISH; + + // + return result; +} +ENUM_X_DIRECTION XOpposit(ENUM_X_DIRECTION value) +{ + return Opposit(value); +} + +/** + * Converts To String ... + * + * @param value: ENUM_X_DIRECTION member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_DIRECTION value) +{ + // + string result = NULL; + + // + switch (value) + { + case X_DIRECTION_ALL: + result = "ALL"; + break; + case X_DIRECTION_NONE: + result = "NONE"; + break; + case X_DIRECTION_BULLISH: + result = "BULLISH"; + break; + case X_DIRECTION_BEARISH: + result = "BEARISH"; + break; + } + + // + return result; +} +string ToXString(ENUM_X_DIRECTION value) +{ + return ToString(value); +} +// +// END Direction ... +// + +// +// START Fibo Level ... +// + +// +// Fibonacci Levels ... +enum ENUM_X_FIBO_LEVELS +{ + X_FIBO_LEVEL_236, // 0.236 + X_FIBO_LEVEL_270, // 0.27 + X_FIBO_LEVEL_382, // 0.382 + X_FIBO_LEVEL_500, // 0.5 + X_FIBO_LEVEL_618, // 0.618 + X_FIBO_LEVEL_730, // 0.730 + X_FIBO_LEVEL_764, // 0.764 + X_FIBO_LEVEL_786, // 0.786 +}; + +// +// Extensions ... + +/** + * Converts To String ... + * + * @param value: ENUM_X_FIBO_LEVELS member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_FIBO_LEVELS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_FIBO_LEVEL_236: + result = "0.236"; + break; + + // + case X_FIBO_LEVEL_270: + result = "0.270"; + break; + + // + case X_FIBO_LEVEL_382: + result = "0.382"; + break; + + // + case X_FIBO_LEVEL_500: + result = "0.500"; + break; + + // + case X_FIBO_LEVEL_618: + result = "0.618"; + break; + + // + case X_FIBO_LEVEL_730: + result = "0.730"; + break; + + // + case X_FIBO_LEVEL_764: + result = "0.764"; + break; + + // + case X_FIBO_LEVEL_786: + result = "0.786"; + break; + } + + // + return result; +} +string ToXString(ENUM_X_FIBO_LEVELS value) +{ + return ToString(value); +} + +/** + * Converts To String ... + * + * @param value: ENUM_X_FIBO_LEVELS member ... + * + * @return ( double ) + */ +double GetFiboLevelValue(ENUM_X_FIBO_LEVELS value) +{ + // + double result = 0; + + // + switch (value) + { + // + case X_FIBO_LEVEL_236: + result = 0.236; + break; + + // + case X_FIBO_LEVEL_270: + result = 0.270; + break; + + // + case X_FIBO_LEVEL_382: + result = 0.382; + break; + + // + case X_FIBO_LEVEL_500: + result = 0.500; + break; + + // + case X_FIBO_LEVEL_618: + result = 0.618; + break; + + // + case X_FIBO_LEVEL_730: + result = 0.730; + break; + + // + case X_FIBO_LEVEL_764: + result = 0.764; + break; + + // + case X_FIBO_LEVEL_786: + result = 0.786; + break; + } + + // + return result; +} + +// +// END Fibo Level ... +// + +// +// START Swing Types ... +// + +// +// Swing Types ... +enum ENUM_X_SWING_TYPE +{ + X_SWING_NONE, // None + X_SWING_LOW, // Swing Low + X_SWING_HIGH, // Swing High +}; + +// +// Extensions ... + +/** + * Validate ... + * + * @param value: ENUM_X_DIRECTION member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_SWING_TYPE value) +{ + // + bool result = false; + + // + result = + value != NULL && + value != X_SWING_NONE; + + // + return result; +} +bool IsXValid(ENUM_X_SWING_TYPE value) +{ + return IsValid(value); +} + +/** + * Converts To String ... + * + * @param value: ENUM_X_SWING_TYPE member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_SWING_TYPE value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_SWING_NONE: + result = "None"; + break; + + // + case X_SWING_LOW: + result = "Swing Low"; + break; + + // + case X_SWING_HIGH: + result = "Swing High"; + break; + } + + // + return result; +} +string ToXString(ENUM_X_SWING_TYPE value) +{ + return ToString(value); +} + +/** + * Converts To ENUM_SERIESMODE ... + * + * @param value: ENUM_X_SWING_TYPE member ... + * + * @return ( ENUM_SERIESMODE ) + */ +ENUM_SERIESMODE ToSeriesMode(ENUM_X_SWING_TYPE value) +{ + // + ENUM_SERIESMODE result = MODE_HIGH; + + // + switch (value) + { + // + case X_SWING_HIGH: + result = MODE_HIGH; + break; + + // + case X_SWING_LOW: + default: + result = MODE_LOW; + break; + } + + // + return result; +} +ENUM_SERIESMODE ToXSeriesMode(ENUM_X_SWING_TYPE value) +{ + return ToSeriesMode(value); +} + +// +// END Swing Types ... +// + +// +// START Period Method ... +// + +// +// Period Calculation Method ... +enum ENUM_X_PERIOD_METHOD +{ + X_PERIOD_NONE, // None + X_PERIOD_AUTO, // Auto Select + X_PERIOD_MANUALLY // Manually +}; + +// +// Extensions ... + +/** + * Validate ... + * + * @param value: ENUM_X_PERIOD_METHOD member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_PERIOD_METHOD value) +{ + // + bool result = false; + + // + result = + value != NULL && + value != X_PERIOD_NONE; + + // + return result; +} +bool IsXValid(ENUM_X_PERIOD_METHOD value) +{ + return IsValid(value); +} + +/** + * Converts To String ... + * + * @param value: ENUM_X_PERIOD_METHOD member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_PERIOD_METHOD value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_PERIOD_NONE: + result = "None"; + break; + + // + case X_PERIOD_AUTO: + result = "Auto Select"; + break; + + // + case X_PERIOD_MANUALLY: + result = "Manually"; + break; + } + + // + return result; +} +string ToXString(ENUM_X_PERIOD_METHOD value) +{ + return ToString(value); +} + +// +// END Period Method ... +// + +// +// START Market Cycles ... +// + +// +// Market Cycles ... +enum ENUM_X_MARKET_CYCLES +{ + X_MARKET_CYCLE_UNKNOWN, // Unknown Cycle + X_MARKET_CYCLE_SHORT, // Short Cycle + X_MARKET_CYCLE_MEDIUM, // Medium Cycle + X_MARKET_CYCLE_LONG, // Long Cycle + X_MARKET_CYCLE_HIND, // Hind Cycle +}; + +// +// Extensions ... + +/** + * Validate ... + * + * @param value: ENUM_X_MARKET_CYCLES member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_MARKET_CYCLES value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + value != X_MARKET_CYCLE_UNKNOWN + // + ; + + // + return result; +} +bool IsXValid(ENUM_X_MARKET_CYCLES value) +{ + return IsValid(value); +} +bool IsSpecifiedValid(ENUM_X_MARKET_CYCLES value) +{ + return IsValid(value); +} + +/** + * Converts an String to it's related Market Cycle ... + * + * @param value: string ... + * + * @return ( ENUM_X_MARKET_CYCLES ) + */ +ENUM_X_MARKET_CYCLES ToCycle(string value) +{ + // + ENUM_X_MARKET_CYCLES result = X_MARKET_CYCLE_UNKNOWN; + + // + ENUM_X_MARKET_CYCLES cycles[]; + int count = GetAllMarketCycles(cycles); + for (int i = 0; i < count; i++) + { + // + ENUM_X_MARKET_CYCLES iCycle = cycles[i]; + string iStr = ToString(iCycle); + + // + if (value == iStr) + { + // + result = iCycle; + break; + } + } + + // + return result; +} +ENUM_X_MARKET_CYCLES ToXCycle(string value) +{ + return ToCycle(value); +} + +/** + * Converts To String ... + * + * @param value: ENUM_X_MARKET_CYCLES member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_MARKET_CYCLES value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_MARKET_CYCLE_UNKNOWN: + result = "Unknown Cycle"; + break; + + // + case X_MARKET_CYCLE_SHORT: + result = "Short Cycle"; + break; + + // + case X_MARKET_CYCLE_MEDIUM: + result = "Medium Cycle"; + break; + + // + case X_MARKET_CYCLE_LONG: + result = "Long Cycle"; + break; + + // + case X_MARKET_CYCLE_HIND: + result = "Hind Cycle"; + break; + } + + // + return result; +} +string ToXString(ENUM_X_MARKET_CYCLES value) +{ + return ToString(value); +} + +/** + * Retrieve All Availabled Market Cycles ... + * + * @param cycles: ENUM_X_MARKET_CYCLES member collection ... + * + * @return ( int ) + */ +int GetAllMarketCycles(ENUM_X_MARKET_CYCLES &cycles[]) +{ + // + ZeroMemory(cycles); + ArrayResize(cycles, 0); + + // + ArrayResize(cycles, ArraySize(cycles) + 1); + cycles[ArraySize(cycles) - 1] = X_MARKET_CYCLE_UNKNOWN; + + // + ArrayResize(cycles, ArraySize(cycles) + 1); + cycles[ArraySize(cycles) - 1] = X_MARKET_CYCLE_SHORT; + + // + ArrayResize(cycles, ArraySize(cycles) + 1); + cycles[ArraySize(cycles) - 1] = X_MARKET_CYCLE_MEDIUM; + + // + ArrayResize(cycles, ArraySize(cycles) + 1); + cycles[ArraySize(cycles) - 1] = X_MARKET_CYCLE_LONG; + + // + ArrayResize(cycles, ArraySize(cycles) + 1); + cycles[ArraySize(cycles) - 1] = X_MARKET_CYCLE_HIND; + + // + int result = ArraySize(cycles); + + // + return result; +} + +// +// END Market Cycles ... +// + +// +// START Week Days ... +// + +// +// Week Days ... +enum ENUM_X_WEEK_DAYS +{ + X_WEEK_DAY_NONE = -1, // None + X_WEEK_DAY_SUNDAY = 0, // Sunday + X_WEEK_DAY_MONDAY = 1, // Monday + X_WEEK_DAY_TUESDAY = 2, // Tuesday + X_WEEK_DAY_WEDNESDAY = 3, // Wednesday + X_WEEK_DAY_THURSDAY = 4, // Thursday + X_WEEK_DAY_FRIDAY = 5, // Friday + X_WEEK_DAY_SATURDAY = 6, // Saturday +}; + +// +// Extensions ... + +/** + * Validate ... + * + * @param value: ENUM_X_WEEK_DAYS member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_WEEK_DAYS value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + value != X_WEEK_DAY_NONE + // + ; + + // + return result; +} +bool IsXValid(ENUM_X_WEEK_DAYS value) +{ + return IsValid(value); +} + +/** + * Converts To String ... + * + * @param value: ENUM_X_WEEK_DAYS member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_WEEK_DAYS value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_WEEK_DAY_NONE: + result = "None"; + break; + + // + case X_WEEK_DAY_SUNDAY: + result = "Sunday"; + break; + + // + case X_WEEK_DAY_MONDAY: + result = "Monday"; + break; + + // + case X_WEEK_DAY_TUESDAY: + result = "Tuesday"; + break; + + // + case X_WEEK_DAY_WEDNESDAY: + result = "Wednesday"; + break; + + // + case X_WEEK_DAY_THURSDAY: + result = "Thursday"; + break; + + // + case X_WEEK_DAY_FRIDAY: + result = "Friday"; + break; + + // + case X_WEEK_DAY_SATURDAY: + result = "Saturday"; + break; + } + + // + return result; +} +string ToXString(ENUM_X_WEEK_DAYS value) +{ + return ToString(value); +} + +// +// END Week Days ... +// + +// +// START Ma Methods ... +// + +// +// Ma Methods ... +enum ENUM_X_MA_METHOD +{ + X_MA_MODE_NONE, // None + X_MA_MODE_SMA, // SMA + X_MA_MODE_EMA, // EMA + X_MA_MODE_LWMA, // LWMA + X_MA_MODE_SMMA, // SMMA +}; + +// +// Extensions ... + +/** + * Validate ... + * + * @param value: ENUM_X_MA_METHOD member ... + * + * @return ( bool ) + */ +bool IsValid(ENUM_X_MA_METHOD value) +{ + // + bool result = false; + + // + result = + // + value != NULL && + value != X_MA_MODE_NONE + // + ; + + // + return result; +} +bool IsXValid(ENUM_X_MA_METHOD value) +{ + return IsValid(value); +} + +/** + * Converts To String ... + * + * @param value: ENUM_X_MA_METHOD member ... + * + * @return ( string ) + */ +string ToString(ENUM_X_MA_METHOD value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_MA_MODE_NONE: + result = "None"; + break; + + // + case X_MA_MODE_SMA: + result = "SMA"; + break; + + // + case X_MA_MODE_EMA: + result = "EMA"; + break; + + // + case X_MA_MODE_LWMA: + result = "LWMA"; + break; + + // + case X_MA_MODE_SMMA: + result = "SMMA"; + break; + } + + // + return result; +} +string ToXString(ENUM_X_MA_METHOD value) +{ + return ToString(value); +} + +/** + * Converts MA Method ... + **/ +ENUM_MA_METHOD ToXMaMethod(ENUM_X_MA_METHOD value) +{ + // + ENUM_MA_METHOD result = MODE_SMA; + + // + if (!IsXValid(value)) + { + return result; + } + + // + switch (value) + { + // + case X_MA_MODE_EMA: + result = MODE_EMA; + break; + + // + case X_MA_MODE_SMA: + result = MODE_SMA; + break; + + // + case X_MA_MODE_LWMA: + result = MODE_LWMA; + break; + + // + case X_MA_MODE_SMMA: + result = MODE_SMMA; + break; + } + + // + return result; +} +ENUM_X_MA_METHOD ToXMaMethod(ENUM_MA_METHOD value) +{ + // + ENUM_X_MA_METHOD result = X_MA_MODE_NONE; + + // + switch (value) + { + // + case MODE_EMA: + result = X_MA_MODE_EMA; + break; + + // + case MODE_SMA: + result = X_MA_MODE_SMA; + break; + + // + case MODE_LWMA: + result = X_MA_MODE_LWMA; + break; + + // + case MODE_SMMA: + result = X_MA_MODE_SMMA; + break; + } + + // + return result; +} + +// +// END Ma Methods ... +// + +// +// START XPivots ... +// + +// +enum ENUM_X_PIVOT_TYPE +{ + X_PIVOT_TYPE_NONE = 0, // None + X_PIVOT_TYPE_PEAK = 1, // PEAK + X_PIVOT_TYPE_VALE = 2, // VALE +}; + +/** + * Validate ... + * + * @param value: ENUM_X_PIVOT_TYPE ... + * + * @return ( bool ) + */ +bool IsXValid(ENUM_X_PIVOT_TYPE value) +{ + // + bool result = false; + + // + result = value != X_PIVOT_TYPE_NONE; + + // + return result; +} + +/** + * Check Specified Type of Pivot is Peak or not ... + * + * @param value: ENUM_X_PIVOT_TYPE, Specified Type ... + * + * @return ( bool ) + */ +bool IsXPeak(ENUM_X_PIVOT_TYPE value) +{ + // + bool result = false; + + // + result = IsXValid(value) && + value == X_PIVOT_TYPE_PEAK; + + // + return result; +} + +/** + * Check Specified Type of Pivot is Vale or not ... + * + * @param value: ENUM_X_PIVOT_TYPE, Specified Type ... + * + * @return ( bool ) + */ +bool IsXVale(ENUM_X_PIVOT_TYPE value) +{ + // + bool result = false; + + // + result = IsXValid(value) && + value == X_PIVOT_TYPE_VALE; + + // + return result; +} + +/** + * Represent Specified ZigZag Point Type as String ... + * + * @param value: ENUM_X_PIVOT_TYPE ... + * + * @return ( string ) + */ +string ToXString(ENUM_X_PIVOT_TYPE value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_PIVOT_TYPE_NONE: + result = "XNONE"; + break; + + // + case X_PIVOT_TYPE_PEAK: + result = "XPEAK"; + break; + + // + case X_PIVOT_TYPE_VALE: + result = "XVALE"; + break; + } + + // + return result; + // return EnumToString(value); +} + +// +// END XPivots ... +// + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.x-guard.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XGuardLib +// Description: All models related to Guard ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" + +// +// Enumeration ... + +// +// Guard Actions ... +enum ENUM_X_GUARD_ACTIONS +{ + X_GUARD_ACTION_NONE, // Nothing to Do + X_GUARD_ACTION_CLOSE, // Close Specified Position + X_GUARD_ACTION_CLOSE_ALL, // Close All Positions + X_GUARD_ACTION_CLOSE_LONGS, // Close All Long Positions + X_GUARD_ACTION_CLOSE_SHORTS, // Close All Short Position + X_GUARD_ACTION_CLOSE_IN_LOSTS, // Close All In Lost Position + X_GUARD_ACTION_CLOSE_IN_PROFITS, // Close All In Profit Position + X_GUARD_ACTION_CLOSE_IN_LOST_LONGS, // Close All In Lost Long Position + X_GUARD_ACTION_CLOSE_IN_PROFIT_LONGS, // Close All In Profit Long Position + X_GUARD_ACTION_CLOSE_IN_LOST_SHORTS, // Close All In Lost Short Position + X_GUARD_ACTION_CLOSE_IN_PROFITS_SHORT, // Close All In Profit Short Position + X_GUARD_ACTION_PARTIAL_CLOSE, // Partial Close Specified Position + X_GUARD_ACTION_TRAIL_STOP, // Trail Stop of Specified Position + X_GUARD_ACTION_TRAIL_TARGET, // Trail Target of Specified Position + X_GUARD_ACTION_HEDGE, // Hedge Specified Positions +}; + +// +// Definitions ... + +// +// Model a Guard Action ... +struct XGuard +{ + // + // Props ... + ENUM_X_GUARD_ACTIONS action; + datetime time; + + // + string symbol; + string provider; + ENUM_TIMEFRAMES period; + + // + // Specified Position ... + ulong ticket; + + // + // Partial Close ... + double volumeMultiplier; + + // + // SL Trial ... + double sl; + + // + // TP Trial ... + double tp; + + // + bool force; + + // + // Constructor ... + XGuard() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + time = NULL; + action = X_GUARD_ACTION_NONE; + + // + symbol = NULL; + period = NULL; + provider = NULL; + + // + ticket = 0; + + // + volumeMultiplier = 0; + + // + sl = 0; + tp = 0; + + // + force = false; + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsSpecifiedValid(time) && + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + IsSpecifiedValid(action) && + IsSpecifiedValid(provider) + // + ; + + if (!result) + { + return result; + } + + // + // Validate Model Based On Specified Guard Actions ... + + // + return result; + } +}; + +// +// Extensions ... + +// +bool IsValid(ENUM_X_GUARD_ACTIONS item) +{ + // + bool result = false; + + // + result = item != X_GUARD_ACTION_NONE; + + // + return result; +} +bool IsSpecifiedValid(ENUM_X_GUARD_ACTIONS item) +{ + return IsValid(item); +} + +/** + * Add Guard to Collection ... + * + * @param guard: XGuard instance ... + * @param guards: XGuard instance Collection ... + * + * @return ( int ) + */ +int AddGuard( + XGuard &guard, + XGuard &guards[] // +) +{ + // + int result = 0; + + // + if (!guard.IsValid()) + { + return result; + } + + // + AddRef( + guard, + guards // + ); + + // + result = ArraySize(guards); + + // + return result; +} + + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.x-ohcl.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Common Library +// -------------------------------------- +// Name: XOHCLLib +// Description: provide all commonly used functions ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +#include "../Libraries/x-saherelm.common.extensions.lib.mq5" + +// +// Describe an Specific Candle ... +struct XOHCL +{ + // + // Props ... + + // + double high; + double open; + double close; + double low; + long volume; + double spread; + + // + string symbol; + datetime time; + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOHCL() + { + Clean(); + } + + // + // Init a Bar ... + // Using Bar Index ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + int barIndex = 0 // Bar Index + ) + { + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + symbol = mSymbol; + period = mPeriod; + + // + time = iTime( + mSymbol, + mPeriod, + barIndex // + ); + + // + open = iOpen( + mSymbol, + mPeriod, + barIndex // + ); + open = NormalizePrice(open, mSymbol); + + // + close = iClose( + mSymbol, + mPeriod, + barIndex // + ); + close = NormalizePrice(close, mSymbol); + + // + high = iHigh( + mSymbol, + mPeriod, + barIndex // + ); + high = NormalizePrice(high, mSymbol); + + // + low = iLow( + mSymbol, + mPeriod, + barIndex // + ); + low = NormalizePrice(low, mSymbol); + + // + spread = iSpread( + mSymbol, + mPeriod, + barIndex // + ); + spread = NormalizePrice(spread, mSymbol); + + // + volume = iTickVolume( + mSymbol, + mPeriod, + barIndex // + ); + + // + bool result = IsValid(); + + // + return result; + } + + // + // Init a Bar ... + // Using Bar Time ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Period + datetime mTime = NULL // Bar Time + ) + { + // + mTime = NormalizeTime(mTime); + + // + int barIndex = iBarShift( + mSymbol, + mPeriod, + mTime, + false // + ); + + // + bool result = Init( + mSymbol, + mPeriod, + barIndex + // + ); + + // + return result; + } + + // + // Tools ... + + // + void Clean() + { + // + low = 0; + high = 0; + open = 0; + close = 0; + spread = 0; + volume = 0; + + // + time = NULL; + symbol = NULL; + period = NULL; + + // + ZeroMemory(this); + } + + // + // Validate Bar ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + low > 0 && + high > 0 && + open > 0 && + close > 0 && + volume > 0 + // + // TODO: Fix in Some Cases for Zero Spread ... + // spread > 0 && + // + ; + + // + return result; + } + + // + int TotalBars() + { + // + int result = 0; + + // + result = iBars( + symbol, + period // + ); + + // + return result; + } + + // + // Calculate X_PRICE Specified Type ... + double GetPrice(ENUM_X_PRICE mPType) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + return GetAppliedPrice( + mPType, + open, + high, + low, + close // + ); + } + + // + // Retrieve Price base On Series Mode ... + double GetPrice(ENUM_SERIESMODE mMode) + { + // + ENUM_X_PRICE mType = ToXPrice(mMode); + + // + return GetPrice(mType); + } + + // + // Calculate Applied Price ... + double GetPrice(ENUM_APPLIED_PRICE mPType) + { + // + ENUM_X_PRICE mType = ToXPrice(mPType); + + // + return GetPrice(mType); + } + + // + // Find Specific Price ... + bool FindHigherPriceBar( + XOHCL &bar, + double price, + ENUM_X_PRICE _type = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = TotalBars(); + result = IsValidSize(totalBars); + if (!result) + { + return result; + } + + // + int start = Index(); + int maxAllowedLoopback = totalBars / 5; + for (int i = start; i < maxAllowedLoopback; i++) + { + // + result = bar.Init( + symbol, + period, + i // + ); + + // + if (!result) + { + break; + } + + // + double iPrice = bar.GetPrice(_type); + + // + result = + // + iPrice > 0 && + iPrice > price + // + ; + if (result) + { + break; + } + } + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + // Find Specific Price ... + bool FindLowerPriceBar( + XOHCL &bar, + double price, + ENUM_X_PRICE _type = X_PRICE_HIGH // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int totalBars = TotalBars(); + result = IsValidSize(totalBars); + if (!result) + { + return result; + } + + // + int start = Index(); + int maxAllowedLoopback = totalBars / 5; + for (int i = start; i < maxAllowedLoopback; i++) + { + // + result = bar.Init( + symbol, + period, + i // + ); + + // + if (!result) + { + break; + } + + // + double iPrice = bar.GetPrice(_type); + + // + result = + // + iPrice > 0 && + iPrice < price + // + ; + if (result) + { + break; + } + } + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + // Calculate up Price ... + double GetUp() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMax(open, close); + + // + return result; + } + + // + // Calculate Down Price ... + double GetDown() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathMin(open, close); + + // + return result; + } + + // + // Calculate Bar Body ... + double GetBody() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetUp() - GetDown(); + + // + return result; + } + + // + // Calculate Bar Range ... + double GetRange() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = high - low; + + // + return result; + } + + // + // Calculate Bar Shadows ... + double GetShadows() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetRange() - GetBody(); + + // + return result; + } + + // + // Calculate Bar High Shadow ... + double GetHighShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + high - GetUp() + // + ; + + // + return result; + } + + // + // Calculate Bar Low Shadow ... + double GetLowShadow() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + GetDown() - low; + // + ; + + // + return result; + } + + // + // Check Bar is Bullish ... + bool IsBullish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open < close; + + // + return result; + } + + // + // Check Bar is Bearish ... + bool IsBearish() + { + // + bool result = false; + + // + if (!IsValid()) + { + return result; + } + + // + result = open > close; + + // + return result; + } + + // + // Get Direction of Bar ... + ENUM_X_DIRECTION GetDirection() + { + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + bool isBullish = IsBullish(); + bool isBearish = IsBearish(); + + // + result = + isBullish && isBearish + ? X_DIRECTION_ALL + : !isBullish && !isBearish + ? X_DIRECTION_NONE + : isBullish + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; + } + + // + // Find Next Bar Time ... + datetime NextAt() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time + prSeconds; + + // + return result; + } + + // + // Find Prev Bar Time ... + datetime BeforeOn() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int prSeconds = PeriodSeconds(period); + + // + result = time - prSeconds; + + // + return result; + } + + // + // Calculate Last Bar Open Time in Smaller Period ... + datetime GetLastBarTimeOfPeriod( + ENUM_TIMEFRAMES smallerPeriod // + ) + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int sourceSeconds = PeriodSeconds(period); + int destSeconds = PeriodSeconds(smallerPeriod); + if (destSeconds >= sourceSeconds) + { + // + result = time; + return result; + } + + // + result = (datetime)((((int)time) + sourceSeconds) - destSeconds); + + // + return result; + } + + // + // Calculate Close Time ... + datetime GetCloseTime() + { + // + datetime result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + int seconds = PeriodSeconds(period); + + // + result = (datetime)(((int)time) + seconds); + + // + return result; + } + + // + bool BarAt( + int index, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + if (index < 0) + { + index = 0; + } + + // + result = bar.Init( + symbol, + period, + index // + ); + + // + return result; + } + + // + bool BarAt( + datetime _time, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + _time = NormalizeTime(_time); + + // + result = bar.Init( + symbol, + period, + _time // + ); + + // + return result; + } + + // + bool BarIn( + ENUM_TIMEFRAMES _period, + XOHCL &bar // + ) + { + // + bool result = false; + + // + bar.Clean(); + + // + result = IsValid() && + IsSpecifiedValid(_period); + if (!result) + { + return result; + } + + // + int index = Index(_period); + result = bar.Init( + symbol, + _period, + index // + ); + + // + return result; + } + + // + // Find Current Bar Index on Chart ... + int Index() + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + result = iBarShift( + symbol, + period, + time + // + ); + + // + return result; + } + + // + int Index(datetime value) + { + // + int result = -1; + + // + value = NormalizeTime(value); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = iBarShift( + symbol, + period, + value // + ); + + // + return result; + } + + // + int Index(ENUM_TIMEFRAMES value) + { + // + int result = -1; + + // + result = IsValid() && + IsSpecifiedValid(value); + if (!result) + { + return result; + } + + // + result = iBarShift( + symbol, + value, + time // + ); + + // + return result; + } + + // + bool GetNextBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int idx = Index(); + result = idx > 0; + if (!result) + { + return result; + } + + // + result = bar.Init( + this.symbol, + this.period, + idx - 1 // + ); + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + bool GetPreviousBar(XOHCL &bar) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + int idx = Index(); + + // + result = bar.Init( + this.symbol, + this.period, + idx + 1 // + ); + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + // + bool HasFiboPressure( + ENUM_X_DIRECTION forDir, + ENUM_X_FIBO_LEVELS level = X_FIBO_LEVEL_382 // + ) + { + // + bool result = false; + + // + result = IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = IsSpecifiedBullish(forDir); + bool isBearish = IsSpecifiedBearish(forDir); + + // + double fiboLevelValue = GetFibonacciLevel( + high, + low, + level, + forDir // + ); + + // + isBullish = + isBullish && + GetDown() > fiboLevelValue; + isBearish = + isBearish && + GetUp() < fiboLevelValue; + + // + result = isBullish || + isBearish; + + // + return result; + } + + // + bool IsRejected( + double price, + ENUM_X_DIRECTION forDir, + bool forceType = false, + bool forcePressure = false // + ) + { + // + bool result = false; + + // + result = IsValid() && + price > 0 && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + bool isBullish = + IsSpecifiedBullish(forDir) && + low < price && + GetDown() > price; + + // + bool isBearish = + IsSpecifiedBearish(forDir) && + high > price && + GetUp() < price; + + // + if (forceType) + { + // + isBullish = + isBullish && + IsBullish(); + + // + isBearish = + isBearish && + IsBearish(); + } + + // + if (forcePressure) + { + // + isBullish = + isBullish && + HasFiboPressure(forDir); + + // + isBearish = + isBearish && + HasFiboPressure(forDir); + } + + // + result = isBullish || + isBearish; + + // + return result; + } + + // + bool IsBreaked( + double price, + ENUM_X_DIRECTION forDir, + ENUM_X_FIBO_LEVELS fibLevel = X_FIBO_LEVEL_500, + ENUM_X_BOUNDARY_PRICE boundaryType = X_BOUNDARY_PRICE_UP_DOWN // + ) + { + // + bool result = false; + + // + result = IsValid() && + price > 0 && + HasDirection(forDir) && + IsSpecifiedValid(boundaryType); + if (!result) + { + return result; + } + + // + bool isUpDownPriceType = boundaryType == X_BOUNDARY_PRICE_UP_DOWN; + + // + bool isBullish = + IsBullish() && + low < price && + high > price && + IsSpecifiedBullish(forDir); + + // + bool isBearish = + IsBearish() && + low < price && + high > price && + IsSpecifiedBearish(forDir); + + // + result = isBullish || + isBearish; + if (result) + { + // + // Calculate Range ... + double range = + isUpDownPriceType + ? GetBody() + : GetRange(); + + // + // Apply Edge Range ... + double iReqRange = + (range / 100) * (GetFiboLevelValue(fibLevel) * 100); + + // + // Calculate Boundary Price ... + double iBoundary = + isUpDownPriceType + ? isBullish + ? GetUp() + : GetDown() + : isBullish + ? high + : low; + + // + // Detect Breaked Value ... + + // + double breakedPrice = + isBullish + ? (high - price) + : (price - low); + + // + result = + breakedPrice >= iReqRange; + } + + // + return result; + } + + // + // Find Highest Bar Index ... + int FindHighestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iHighest( + symbol, + period, + mMode, + mLength, + Index()); + + // + return result; + } + + // + // Find Highest ... + double FindHighest( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindHighestIndex( + mLength, + mMode); + if (idx <= -1) + { + return result; + } + + // + XOHCL iH; + result = iH.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iH.GetPrice(mMode); + + // + return result; + } + + /** + * Detect Highest of Specified Price type in Market ... + * + * @param index: souble, reference to hold detected Value Bar index ... + * @param mLength: int, Specified Loopback Length ... + * @param mPriceType: ENUM_X_PRICE, Specified Price type to Detect ... + * + * @return ( double ) + */ + double FindHighest( + int &index, // Index ... + int mLength, // Loopback ... + ENUM_X_PRICE mPriceType // Price Type ... + ) + { + // + double result = EMPTY_VALUE; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + mLength = NormalizeInt(mLength, 1); + + // + // Validate ... + bool has = IsValid() && + IsXValid(mPriceType); + if (!has) + { + return result; + } + + // + XOHCL iBar; + int start = Index(); + int end = start + mLength; + double iValue = EMPTY_VALUE; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + has = BarAt(i, iBar); + if (!has) + { + continue; + } + + // + // Calculate Price ... + iValue = iBar.GetPrice(mPriceType); + + // + // Compare Price With Prev Detected ... + has = !NotEmptyZero(result) + ? true + : iValue > result; + if (has) + { + // + index = i; + result = iValue; + } + } + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; + } + + // + // Find Highest ... + double FindHighestUp( + int mLength // Loopback ... + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = FindHighest(mLength, MODE_OPEN); + result = MathMax(mLength, FindHighest(mLength, MODE_CLOSE)); + + // + return result; + } + + // + // Find Lowest Bar Index ... + int FindLowestIndex( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (mLength < 2) + { + mLength = 2; + } + + // + result = iLowest( + symbol, + period, + mMode, + mLength, + Index()); + + // + return result; + } + + // + // Find Lowest ... + double FindLowest( + int mLength, // Loopback ... + ENUM_SERIESMODE mMode // Calculation mode + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + int idx = FindLowestIndex( + mLength, + mMode); + if (idx <= -1) + { + return result; + } + + // + XOHCL iL; + result = iL.Init( + symbol, + period, + idx + // + ); + if (!result) + { + return result; + } + + // + result = iL.GetPrice(mMode); + + // + return result; + } + + /** + * Detect Lowest of Specified Price type in Market ... + * + * @param index: souble, reference to hold detected Value Bar index ... + * @param mLength: int, Specified Loopback Length ... + * @param mPriceType: ENUM_X_PRICE, Specified Price type to Detect ... + * + * @return ( double ) + */ + double FindLowest( + int &index, // Index ... + int mLength, // Loopback ... + ENUM_X_PRICE mPriceType // Price Type ... + ) + { + // + double result = EMPTY_VALUE; + + // + // Prepare ... + index = -1; + + // + // Normalize ... + mLength = NormalizeInt(mLength, 1); + + // + // Validate ... + bool has = IsValid() && + IsXValid(mPriceType); + if (!has) + { + return result; + } + + // + XOHCL iBar; + int start = Index(); + int end = start + mLength; + double iValue = EMPTY_VALUE; + for (int i = start; i < end; i++) + { + // + iBar.Clean(); + has = BarAt(i, iBar); + if (!has) + { + continue; + } + + // + // Calculate Price ... + iValue = iBar.GetPrice(mPriceType); + + // + // Compare Price With Prev Detected ... + has = !NotEmptyZero(result) + ? true + : iValue < result; + if (has) + { + // + index = i; + result = iValue; + } + } + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; + } + + // + // Find Lowest ... + double FindLowesttDown( + int mLength // Loopback ... + ) + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = FindLowest(mLength, MODE_OPEN); + result = MathMax(mLength, FindLowest(mLength, MODE_CLOSE)); + + // + return result; + } + + // + // Swing Detection ... + + // + int FindSwing( + ENUM_X_SWING_TYPE type, + int shoulders = 3 // + ) + { + // + int result = -1; + + // + // Validate ... + bool isValid = IsValid() && + IsXValid(type); + if (!isValid) + { + return result; + } + + // + // Find Next Swing ... + result = FindXSwing( + type, + symbol, + period, + Index(), + shoulders // + ); + + // + return result; + } + + // + int FindNextSwing( + ENUM_X_SWING_TYPE type, + int shoulders = 3 // + ) + { + // + int result = -1; + + // + // Validate ... + bool isValid = IsValid() && + IsXValid(type); + if (!isValid) + { + return result; + } + + // + // Find Next Swing ... + result = FindXSwing( + type, + symbol, + period, + Index() + 1, + shoulders // + ); + + // + return result; + } + + // + bool FindSwingBar( + ENUM_X_SWING_TYPE type, + XOHCL &swingBar, + int shoulders = 3 // + ) + { + // + bool result = false; + + // + // Prepare ... + swingBar.Clean(); + + // + // Validate ... + result = IsValid() && + IsXValid(type); + if (!result) + { + return result; + } + + // + // Find Next Swing ... + int idx = FindXSwing( + type, + symbol, + period, + Index(), + shoulders // + ); + result = IsValidIndex(idx); + if (!result) + { + return result; + } + + // + result = swingBar.Init( + symbol, + period, + idx // + ); + + // + return result; + } + + // + bool FindNextSwingBar( + ENUM_X_SWING_TYPE type, + XOHCL &swingBar, + int shoulders = 3 // + ) + { + // + bool result = false; + + // + // Prepare ... + swingBar.Clean(); + + // + // Validate ... + result = IsValid() && + IsXValid(type); + if (!result) + { + return result; + } + + // + // Find Next Swing ... + int idx = FindXSwing( + type, + symbol, + period, + Index() + 1, + shoulders // + ); + result = IsValidIndex(idx); + if (!result) + { + return result; + } + + // + result = swingBar.Init( + symbol, + period, + idx // + ); + + // + return result; + } + + // + // Same Checkers ... + + // + bool IsSameAs(XOHCL &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + IsSameTime(item) && + IsSameMarket(item); + + // + return result; + } + + // + bool IsSameTime(XOHCL &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + time == item.time; + + // + return result; + } + + // + bool IsSameSymbol(XOHCL &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + symbol == item.symbol; + + // + return result; + } + + // + bool IsSamePeriod(XOHCL &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + period == item.period; + + // + return result; + } + + // + bool IsSameMarket(XOHCL &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + IsSameSymbol(item) && + IsSamePeriod(item); + + // + return result; + } + + // + // Other ... + string GetTag(string prefix = "") + { + // + string result = NULL; + + // + result = + (IsSpecifiedValid(prefix) + ? prefix + "_" + : "") + + "XOHCL_" + symbol + "_" + ToXString(period) + "_" + ToFormatString(time); + + // + return result; + } + + // + // Convert to String Representation ... + string ToString() + { + // + string result = ""; + + // + result = GetTypeName(this) + + "(O(" + ToXString(open) + "),H(" + ToXString(high) + "),C(" + ToXString(close) + "),L(" + ToXString(low) + "))"; + + // + return result; + } +}; + +// +// Models ... + +// +// Model a Bar Remains Time ... +struct XBarRemainsTime +{ + // + int days; + int hours; + int minutes; + int seconds; + + // + // Constructor ... + XBarRemainsTime() + { + Clean(); + } + + // + // Always Calculate Current 0 Bar Timing ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int minuteSecoonds = 60; + int hourSeconds = minuteSecoonds * 60; + int daySeconds = 24 * hourSeconds; + + // + int periodSeconds = PeriodSeconds( + mPeriod); + datetime startTime = GetBarTime( + mSymbol, + mPeriod, + 0 + // + ); + + // + int secondsDiff = (int)startTime + periodSeconds - (int)TimeCurrent(); + + // + int mWorkingSecondsDiff = secondsDiff; + if (mWorkingSecondsDiff > daySeconds) + { + // + days = mWorkingSecondsDiff / daySeconds; + mWorkingSecondsDiff -= days * daySeconds; + } + if (mWorkingSecondsDiff > hourSeconds) + { + // + hours = mWorkingSecondsDiff / hourSeconds; + mWorkingSecondsDiff -= hours * hourSeconds; + } + if (mWorkingSecondsDiff > minuteSecoonds) + { + // + minutes = mWorkingSecondsDiff / minuteSecoonds; + mWorkingSecondsDiff -= minutes * minuteSecoonds; + } + seconds = mWorkingSecondsDiff; + + // + result = true; + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + days = 0; + hours = 0; + minutes = 0; + seconds = 0; + + // + ZeroMemory(this); + } + + // + // To String Representation ... + string ToString( + string dayId = "d", + string hourId = "h", + string minuteId = "m", + string secondId = "s", + string idSeparator = ": ", + string separator = ", ", + bool ignoreZeroValues = true + // + ) + { + // + string result = ""; + + // + // Days ... + if (!ignoreZeroValues || days > 0) + { + result += dayId + idSeparator + (string)days + separator; + } + + // + // Hours ... + if (!ignoreZeroValues || hours > 0) + { + // + string strHour = ToXString(hours); + if (StringLen(strHour) == 1) + { + strHour = "0" + strHour; + } + + // + result += hourId + idSeparator + strHour + separator; + } + + // + // Minutes ... + if (!ignoreZeroValues || minutes > 0) + { + // + string strMinute = ToXString(minutes); + if (StringLen(strMinute) == 1) + { + strMinute = "0" + strMinute; + } + + // + result += minuteId + idSeparator + strMinute + separator; + } + + // + // Seconds ... + if (!ignoreZeroValues || seconds > 0) + { + // + string strSec = ToXString(seconds); + if (StringLen(strSec) == 1) + { + strSec = "0" + strSec; + } + + // + result += secondId + idSeparator + strSec; + } + + // + return result; + } +}; + +// +// Tracking Times ... +struct XTimeTracker +{ + // + // Props ... + int xMonth; + int xDayOfWeek; + int xForWeekDay; + int xDay; + int xHour; + int xMinute; + + // + // Constructor ... + XTimeTracker() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + xDay = -1; + xHour = -1; + xMonth = -1; + xMinute = -1; + xDayOfWeek = -1; + xForWeekDay = -1; + + // + ZeroMemory(this); + } + + // + // Detecting New Minute ... + bool IsNewMinute() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.min != xMinute; + if (result) + { + xMinute = timeStruct.min; + } + + // + return result; + } + + // + // Detecting New Houre ... + bool IsNewHour() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.hour != xHour; + if (result) + { + xHour = timeStruct.hour; + } + + // + return result; + } + + // + // Detecting New Day ... + bool IsNewDay() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.day_of_year != xDay; + if (result) + { + xDay = timeStruct.day_of_year; + } + + // + return result; + } + + // + // Detecting New Week ... + bool IsNewWeek() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Week ... + // Since Week Starts From Monday in Forex World ... + // we Calculate Start of Week by 1-Monday ... + result = + xDayOfWeek == -1 && + xForWeekDay == -1 + ? true + : timeStruct.day_of_week == 1 && + timeStruct.day_of_year > xForWeekDay; + + // + xForWeekDay = timeStruct.day_of_year; + xDayOfWeek = timeStruct.day_of_week; + + // + return result; + } + + // + // Detecting End Of Week ... + bool IsWeekEnd() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check WeekEnd ... + // Since Week Starts From Monday in Forex World ... + // we Calculate End of Week by 5-Friday ... + result = + xDayOfWeek != -1 && + timeStruct.day_of_week == 5 && + timeStruct.hour == 23 && + timeStruct.min == 59 && + timeStruct.sec == 59; + + // + return result; + } + + // + // Detecting New Month ... + bool IsNewMonth() + { + // + bool result = false; + + // + // Retrieve Current Time as Struct ... + MqlDateTime timeStruct = GetCurrentTime(); + + // + // Check Houre ... + result = timeStruct.mon != xMonth; + if (result) + { + xMonth = timeStruct.mon; + } + + // + return result; + } +}; + +// +// Tracking Bars on Specified Environment ... +struct XBarTracker +{ + // + string symbol; // Tracking Symbol + ENUM_TIMEFRAMES period; // Tracking Time Frame + + // + int lastTrackedBar; // Last Tracked Bar ... + + // + bool waitsUntilNext; // Waits Until Next Bar ... + + // + // Constructor ... + XBarTracker() + { + Clean(); + } + + // + // Initializer ... + bool Init( + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL // Trading Period + ) + { + // + bool result = false; + + // + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + this.symbol = mSymbol; + this.period = mPeriod; + + // + this.lastTrackedBar = 0; + + // + result = true; + + // + return result; + } + + // + // Retrieve all Bars ... + int CountBars() + { + // + return iBars( + symbol, + period + // + ); + } + + // + // Check if it's New Bar ... + bool IsNewBar() + { + // + bool result = false; + + // + int currentBars = CountBars(); + + // + result = currentBars > lastTrackedBar; + if (result) + { + lastTrackedBar = currentBars; + } + + // + return result; + } + + // + bool CanProcessBar() + { + // + bool _isInTestMode = IsRunningOnTestMode(); + + // + bool isNewBar = IsNewBar(); + + // + bool result = + _isInTestMode + ? isNewBar + : !waitsUntilNext + ? true + : isNewBar; + if (result && waitsUntilNext) + { + waitsUntilNext = false; + } + + // + return result; + } + + // + void Waits() + { + this.waitsUntilNext = true; + } + + // + // Tools ... + void Clean() + { + // + symbol = NormalizeSymbol(NULL); + period = NormalizePeriod(NULL); + + // + ZeroMemory(this); + } + + // + bool GetBar( + XOHCL &bar, + int index = 0 // + ) + { + // + bool result = false; + + // + result = bar.Init( + symbol, + period, + index // + ); + + // + return result; + } + + // + bool GetBar( + XOHCL &bar, + datetime time = NULL // + ) + { + // + bool result = false; + + // + NormalizeTime(time); + + // + int barIndex = iBarShift( + symbol, + period, + time, + false // + ); + + // + result = barIndex >= 0; + if (!result) + { + return result; + } + + // + result = bar.Init( + symbol, + period, + barIndex // + ); + + // + return result; + } + + // + int Index(datetime time = NULL) + { + // + int result = 0; + + // + NormalizeTime(time); + + // + result = iBarShift( + symbol, + period, + time, + false // + ); + + // + return result; + } +}; + +// +// Extensions ... + +// +// Extract Specific Range of Bars ... +// using Start Bar Index ... +int GetBars( + XOHCL &bars[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + int from = 0, // Start Bar Index + int count = 1 // Number of Bars +) +{ + // + int result = 0; + + // + from = NormalizeInt(from); + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int total = Bars( + mSymbol, + mPeriod // + ); + if (from > total - 2) + { + from = total - 2; + } + + // + if (count < 0) + { + count = 1; + } + + // + int start = from; + int end = start + count; + if (end > total - 1) + { + end = total - 1; + } + + // + Clean(bars); + + // + for (int i = start; i < end; i++) + { + // + XOHCL iBar; + bool isValid = iBar.Init( + mSymbol, + mPeriod, + i // + ); + + // + if (isValid) + { + // + AddRef( + iBar, + bars // + ); + } + } + + // + result = ArraySize(bars); + + // + return result; +} + +// +// Extract Specific Range of Bars ... +// using Start Bar Time ... +int GetBars( + XOHCL &bars[], // Hold Result + string mSymbol = NULL, // Trading Symbol + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Time Frame + datetime from = NULL, // Start Bar Time + int count = 1 // Number of Bars +) +{ + // + from = NormalizeTime(from); + mSymbol = NormalizeSymbol(mSymbol); + mPeriod = NormalizePeriod(mPeriod); + + // + int barIndex = GetBarIndex( + mSymbol, + mPeriod, + from // + ); + + // + return GetBars( + bars, + mSymbol, + mPeriod, + barIndex, + count // + ); +} + +/** + * Remove Specified Item from a Collection ... + * + * @param item: Specified Item ... + * @param source: Specified Collection for Remove item from it ... + * + * @return ( bool ) + */ +bool Remove( + XOHCL &item, + XOHCL &source[] // +) +{ + // + bool result = false; + + // + result = + item.IsValid() && + HasChild(source); + if (!result) + { + return result; + } + + // + int idx = -1; + result = FindIndex( + idx, + item, + source // + ); + if (!result) + { + return result; + } + + // + result = ArrayRemove( + source, + idx, + 1 // + ); + + // + return result; +} + +/** + * Remove Specified items from a Collection ... + * + * @param items: Specified Items to Remove ... + * @param sources: Sepcified Collection for Removing items from it ... + * + * @return ( int ) + */ +int Removes( + XOHCL &items[], + XOHCL &sources[] // +) +{ + // + int result = 0; + + // + bool has = HasChild(items) && + HasChild(sources); + if (!has) + { + return result; + } + + // + int idx = -1; + has = false; + int count = ArraySize(items); + for (int i = 0; i < count; i++) + { + // + // Detect Item Index in Collection ... + has = FindIndex( + idx, + items[i], + sources // + ); + if (has) + { + // + // Remove Detected Index from Collection ... + has = ArrayRemove( + sources, + idx, + 1 // + ); + + // + if (has) + { + // + // Count Removed Items ... + result++; + } + } + } + + // + return result; +} + +/** + * Find Specified Item index in a Collection ... + * + * @param index: int, reference to Hold Index if Exists ... + * @param item: Specified item to Detect ... + * @param source: Collection to Search for item ... + * + * @return ( bool ) + */ +bool FindIndex( + int &index, + XOHCL &item, + XOHCL &source[] // +) +{ + // + bool result = false; + + // + index = -1; + + // + int count = ArraySize(source); + result = item.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isSame = item.IsSameAs(source[i]); + if (isSame) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; +} + +/** + * Add Specified Item to Specified Collection, if not Exists ... + * + * @param item: Item to Add ... + * @param sources: Collection to Add item ... + * @param maxAllowed: int, Max Allowed Collection Size ... + * + * @return ( bool ) + */ +bool AddIfNotExists( + XOHCL &item, + XOHCL &sources[], + int maxAllowed = 0 // +) +{ + // + bool result = false; + + // + // Validate Args ... + result = item.IsValid(); + if (!result) + { + return result; + } + + // + // Check Item Exists or not ... + int idx = -1; + bool isExists = FindIndex( + idx, + item, + sources // + ); + result = !isExists; + if (!result) + { + return result; + } + + // + AddRef( + item, + sources // + ); + + // + // Handle Cleanup Collection + // if Max Reached ... + if (result && + maxAllowed > 0) + { + // + CleanupArray( + sources, + maxAllowed // + ); + } + + // + return result; +} + +/** + * Get Oldest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetOldest( + XOHCL &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XOHCL selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + !selected.IsValid() + ? true + : selected.time > source[i].time; + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Youngest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetYoungest( + XOHCL &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XOHCL selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + !selected.IsValid() + ? true + : selected.time < source[i].time; + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Lowest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetLowest( + XOHCL &source[], + ENUM_X_PRICE _priceType = X_PRICE_LOW // +) +{ + // + int result = -1; + + // + if (!IsXValid(_priceType)) + { + _priceType = X_PRICE_LOW; + } + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XOHCL selected; + double iPrice = EMPTY_VALUE; + double selectedPrice = EMPTY_VALUE; + for (int i = 0; i < count; i++) + { + // + iPrice = source[i].GetPrice(_priceType); + selectedPrice = selected.GetPrice(_priceType); + + // + bool canSet = + !selected.IsValid() + ? true + : selectedPrice > iPrice; + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Highest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param _priceType: Specified Price type ... + * + * @return ( int ) + */ +int GetHighest( + XOHCL &source[], + ENUM_X_PRICE _priceType = X_PRICE_HIGH // +) +{ + // + int result = -1; + + // + if (!IsXValid(_priceType)) + { + _priceType = X_PRICE_HIGH; + } + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XOHCL selected; + double iPrice = EMPTY_VALUE; + double selectedPrice = EMPTY_VALUE; + for (int i = 0; i < count; i++) + { + // + iPrice = source[i].GetPrice(_priceType); + selectedPrice = selected.GetPrice(_priceType); + + // + bool canSet = + !selected.IsValid() + ? true + : selectedPrice < iPrice; + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Nearest Directional Bar ... + * + * @param bar: XOHCL, reference to Specified Start Bar ... + * @param directionalBar: XOHCL, reference to hold Detected Bar ... + * @param forDir: ENUM_X_DIRECTION, Specified Which Directional Bar looking for ... + * @param loopback: int, Loopback Length ... + * + * @return ( bool ) + */ +bool GetDirectionalBar( + XOHCL &bar, + XOHCL &directionalBar, + ENUM_X_DIRECTION forDir, + int loopback = 1500 // +) +{ + // + bool result = false; + + // + // Prepare ... + directionalBar.Clean(); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 1); + + // + // Validate ... + result = bar.IsValid() && + HasDirection(forDir); + if (!result) + { + return result; + } + + // + int start = bar.Index() + 1; + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + directionalBar.Clean(); + result = bar.BarAt(i, directionalBar); + result = result && + directionalBar.GetDirection() == forDir; + if (result) + { + break; + } + + // + directionalBar.Clean(); + } + + // + result = directionalBar.IsValid() && + forDir == directionalBar.GetDirection(); + + // + // Cleanup Resources ... + if (!result) + { + directionalBar.Clean(); + } + + // + return result; +} + +/** + * Get Nearest Breaker Bar of Specified Bar's Price ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param breaker: XOHCL, reference to hold Detected Breaker Bar ... + * @param priceType: ENUM_X_PRICE, which price type of Bar to Check to Break ... + * @param breakType: ENUM_X_PRICE, which price of Breaker Bar must Breke price ... + * @param breakDir: ENUM_X_DIRECTION, Specified Break Direction ... + * @param loopback: int, Max Allowed Loopback to Detect Breaker Bar ... + * + * @return ( bool ) + */ +bool GetBreakerBar( + XOHCL &bar, + XOHCL &breaker, + ENUM_X_PRICE priceType, + ENUM_X_PRICE breakType, + ENUM_X_DIRECTION breakDir, + int loopback = 1500 // +) +{ + // + // PriceType: which Applied Price of Specified Bar must to Check for Break ... + + // + // BreakType: which Applied Price of breakerBar must Break price ... + + // + // BreakDir: + // ----------- + // Bullish: Price Must Break Applied Price from Down to Top ... + // Bearish: Price must Break Applied Price from Top to Down ... + + // + bool result = false; + + // + // Prepare ... + breaker.Clean(); + + // + // Normalize ... + loopback = NormalizeInt(loopback, 1); + + // + // Validate ... + result = bar.IsValid() && + IsXValid(priceType) && + IsXValid(breakType) && + HasDirection(breakDir); + if (!result) + { + return result; + } + + // + double iPrice = EMPTY_VALUE; + bool isBullish = IsXBullish(breakDir); + double price = bar.GetPrice(priceType); + + // + int start = bar.Index(); + int end = start + loopback; + for (int i = start; i < end; i++) + { + // + breaker.Clean(); + iPrice = EMPTY_VALUE; + + // + // Initialize Indexed Bar ... + result = bar.BarAt(i, breaker); + if (!result) + { + breaker.Clean(); + break; + } + + // + // Check Breake ... + iPrice = breaker.GetPrice(breakType); + result = + isBullish + ? iPrice > price + : iPrice < price; + if (result) + { + break; + } + } + + // + result = breaker.IsValid(); + + // + // Cleanup Resources ... + if (!result) + { + breaker.Clean(); + } + + // + return result; +} + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.x-pivot.analysis.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XPOILib +// Description: All models related to POIs ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2025, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.extensions.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.lib.mq5" + +/** + * Model Specified Pivots Analysis ... + **/ +struct XPivotAnalysis +{ + // + // Props ... + string name; // Name ... + string symbol; // Symbol ... + datetime time; // Time ... + XPivot pivots[]; // Pivots ... + ENUM_TIMEFRAMES period; // Period ... + + // + // Linear Regression Parameters ... + double peakSlope; + double valeSlope; + double peakIntercept; + double valeIntercept; + + // + // Analysed Results ... + + // + // Directions ... + ENUM_X_DIRECTION dir; // Trending Direction ... + ENUM_X_DIRECTION peakDir; + ENUM_X_DIRECTION valeDir; + + // + // Predicted Values ... + double peakTo; + double valeTo; + double peakFrom; + double valeFrom; + + // + // Time Analysis ... + datetime toTime; + datetime fromTime; + + // + // Support and Resistances ... + double minorSupport; + double majorSupport; + double minorResistance; + double majorResistance; + + // + // Constructor ... + XPivotAnalysis() + { + Clean(); + } + + // + // Tools ... + + // + // Cleaners ... + + /** + * Cleanup Model ... + */ + void Clean() + { + // + time = NULL; + name = NULL; + symbol = NULL; + period = NULL; + SpecifiedClean(pivots); + + // + CleanAnalysis(); + CleanLinearRegressionParameters(); + + // + ZeroMemory(this); + } + + /** + * Clean Analysis Props ... + */ + void CleanAnalysis() + { + // + toTime = NULL; + fromTime = NULL; + peakTo = EMPTY_VALUE; + valeTo = EMPTY_VALUE; + peakFrom = EMPTY_VALUE; + valeFrom = EMPTY_VALUE; + dir = X_DIRECTION_NONE; + peakDir = X_DIRECTION_NONE; + valeDir = X_DIRECTION_NONE; + minorSupport = EMPTY_VALUE; + majorSupport = EMPTY_VALUE; + minorResistance = EMPTY_VALUE; + majorResistance = EMPTY_VALUE; + } + + /** + * Clean Linear Regression Parameters ... + */ + void CleanLinearRegressionParameters() + { + // + peakSlope = EMPTY_VALUE; + valeSlope = EMPTY_VALUE; + peakIntercept = EMPTY_VALUE; + valeIntercept = EMPTY_VALUE; + } + + // + // Initializer / Actions (s) ... + + /** + * Initialize Model ... + * + * @param _name: Name ... + * @param _symbol: Symbol ... + * @param _period: Period ... + * @param _pivots: Provided Pivots ... + * + * @return ( bool ) + */ + bool Init( + string _name, + string _symbol, + ENUM_TIMEFRAMES _period, + XPivot &_pivots[] // + ) + { + // + bool result = false; + + // + // Validate Args ... + result = + HasChild(_pivots) && + IsSpecifiedValid(_name) && + IsSpecifiedValid(_symbol) && + IsSpecifiedValid(_period); + if (!result) + { + // + Clean(); + return result; + } + + // + name = _name; + symbol = _symbol; + period = _period; + Copy( + _pivots, + pivots // + ); + time = TimeCurrent(); + + // + result = IsValid(); + if (!result) + { + Clean(); + } + + // + // Do Calculations if Model is Valid ... + if (result) + { + Update(); + } + + // + return result; + } + + /** + * Fully Update Analysis based on Pivots ... + */ + void Update() + { + // + bool has = false; + + // + // Prepare ... + CleanAnalysis(); + CleanLinearRegressionParameters(); + + // + // Validate ... + has = IsValid() && + HasPivots(); + if (!has) + { + return; + } + + // + // Calculate Linear Regression Parameters ... + has = CalculateLinearRegressionParameters(); + if (!has) + { + return; + } + + // + // Analyse ... + has = Analyse(); + if (!has) + { + return; + } + } + + /** + * Fully Update Analysis based on Pivots ... + * + * @param _pivots: new Pivots Collection for Update ... + */ + void Update(XPivot &_pivots[]) + { + // + bool has = + IsValid() && + HasChild(_pivots); + if (!has) + { + return; + } + + // + SpecifiedClean(pivots); + Copy( + _pivots, + pivots // + ); + + // + Update(); + } + + /** + * Re Analyse Pivots ... + * + * @return ( bool ) + */ + bool Analyse() + { + // + bool result = false; + + // + // Prepare ... + CleanAnalysis(); + + // + // Validate ... + result = IsValid() && + HasPivots() && + HasLinearRegressionParameters(); + if (!result) + { + return result; + } + + // + // Do Analyse ... + + // + bool has = false; + + // + // Specified To and From Time ... + + // + // To Time ... + int toIDX = GetYoungest(pivots); + if (IsValidIndex(toIDX)) + { + // + toTime = pivots[toIDX].time; + toIDX = GetBarIndex( + symbol, + period, + toTime // + ); + } + + // + // From Time ... + int fromIDX = GetOldest(pivots); + if (IsValidIndex(fromIDX)) + { + // + fromTime = pivots[fromIDX].time; + fromIDX = GetBarIndex( + symbol, + period, + fromTime // + ); + } + + // + // Validate To From times ... + result = + IsValidIndex(toIDX) && + IsValidIndex(fromIDX) && + IsSpecifiedValid(toTime) && + IsSpecifiedValid(fromTime); + if (!result) + { + return result; + } + + // + // Predict Values ... + + // + // Peaks ... + + // + // Check Slope and Intercept Exists ... + has = NotEmpty(peakSlope) && + NotEmpty(peakIntercept); + if (has) + { + // + // To ... + peakTo = PredictValue( + peakSlope, + peakIntercept, + toIDX // + ); + + // + // From ... + peakFrom = PredictValue( + peakSlope, + peakIntercept, + fromIDX // + ); + } + + // + // Vales ... + + // + // Check Slope and Intercept Exists ... + has = NotEmpty(valeSlope) && + NotEmpty(valeIntercept); + if (has) + { + // + // To ... + valeTo = PredictValue( + valeSlope, + valeIntercept, + toIDX // + ); + + // + // From ... + valeFrom = PredictValue( + valeSlope, + valeIntercept, + fromIDX // + ); + } + + // + // Check Directions ... + + // + // Peak ... + has = IsPeakAnalysed(); + if (has) + { + // + peakDir = + peakFrom < peakTo + ? X_DIRECTION_BULLISH + : peakFrom > peakTo + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + // Vale ... + has = IsValeAnalysed(); + if (has) + { + // + valeDir = + valeFrom < valeTo + ? X_DIRECTION_BULLISH + : valeFrom > valeTo + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + // Check For Strong Type Trending ... + has = + IsPeakAnalysed() && + IsValeAnalysed() && + peakDir == valeDir; + if (has) + { + dir = peakDir; + } + + // + // Calculate Support and Resistances ... + + // + // Support ... + ExtractSupport( + minorSupport, + majorSupport, + pivots // + ); + + // + // Resistance ... + ExtractResistances( + minorResistance, + majorResistance, + pivots // + ); + + // + result = IsAnalysed(); + + // + // Cleanup Resources ... + + // + return result; + } + + /** + * Re Calculate Linear Regression Parameters ... + * + * @return ( bool ) + */ + bool CalculateLinearRegressionParameters() + { + // + bool result = false; + + // + // Prepare ... + CleanLinearRegressionParameters(); + + // + // Validate ... + result = IsValid() && + HasPivots(); + if (!result) + { + return result; + } + + // + // Make a Copy of Pivots ... + XPivot tmpPivots[]; + Copy( + pivots, + tmpPivots // + ); + + // + // Sort Pivots ... + Sort( + tmpPivots, + X_SORT_BY_DATE, + X_DIRECTION_BEARISH // + ); + + // + // Do Calculations ... + + // + double yData[]; + double xData[]; + bool has = false; + + // + // Peaks ... + + // + XPivot peaks[]; + int peaksCount = ExtractPivots( + peaks, + tmpPivots, + X_PIVOT_TYPE_PEAK // + ); + has = IsValidSize(peaksCount); + if (has) + { + // + // Extract X and Y axis Data ... + ExtractPivotsData( + xData, + yData, + peaks // + ); + + // + // Calculating Slope and Intercept ... + has = ArraySize(xData) >= 2 && + ArraySize(yData) >= 2; + if (has) + { + // + CalculateSlopeAndIntercept( + peakSlope, + peakIntercept, + xData, + yData // + ); + } + } + + // + // Vales ... + + // + XPivot vales[]; + int valesCount = ExtractPivots( + vales, + tmpPivots, + X_PIVOT_TYPE_VALE // + ); + has = IsValidSize(valesCount); + if (has) + { + // + // Extract X and Y axis Data ... + ExtractPivotsData( + xData, + yData, + vales // + ); + + // + // Calculating Slope and Intercept ... + has = ArraySize(xData) >= 2 && + ArraySize(yData) >= 2; + if (has) + { + // + CalculateSlopeAndIntercept( + valeSlope, + valeIntercept, + xData, + yData // + ); + } + } + + // + // Validate Result ... + result = + IsValid() && + HasLinearRegressionParameters(); + + // + // Cleanup Resources ... + SpecifiedClean(yData); + SpecifiedClean(xData); + SpecifiedClean(peaks); + SpecifiedClean(vales); + SpecifiedClean(tmpPivots); + + // + return result; + } + + // + // Validator / Checker (s) ... + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + HasPivots() && + IsSpecifiedValid(time) && + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period); + + // + return result; + } + + /** + * Check Model has Pivots or not ... + * + * @return ( bool ) + */ + bool HasPivots() + { + // + bool result = false; + + // + result = HasChild(pivots); + + // + return result; + } + + /** + * Check Model is Analysed or not ... + * + * @return ( bool ) + */ + bool IsAnalysed() + { + // + bool result = false; + + // + result = + IsPeakAnalysed() || + IsValeAnalysed(); + + // + return result; + } + + /** + * Check Peak Analysed or not ... + * + * @return ( bool ) + */ + bool IsPeakAnalysed() + { + // + bool result = false; + + // + result = + IsValid() && + HasLinearRegressionParameters() && + ( + // + NotEmpty(peakTo) && + NotEmpty(peakFrom) && + // HasDirection(peakDir) && + IsSpecifiedValid(toTime) && + IsSpecifiedValid(fromTime) + // + ); + + // + return result; + } + + /** + * Check Vale Analysed or not ... + * + * @return ( bool ) + */ + bool IsValeAnalysed() + { + // + bool result = false; + + // + result = + IsValid() && + HasLinearRegressionParameters() && + ( + // + NotEmpty(valeTo) && + NotEmpty(valeFrom) && + // HasDirection(valeDir) && + IsSpecifiedValid(toTime) && + IsSpecifiedValid(fromTime) + // + ); + + // + return result; + } + + /** + * Check Models Linear Regression Parameters Calculated or not ... + * + * @return ( bool ) + */ + bool HasLinearRegressionParameters() + { + // + bool result = false; + + // + result = + (NotEmpty(peakSlope) && + NotEmpty(peakIntercept)) || + (NotEmpty(valeSlope) || + NotEmpty(valeIntercept)); + + // + return result; + } + + /** + * Check Analysis Has Trend or not ... + * + * @return ( bool ) + */ + bool HasTrend() + { + // + bool result = false; + + // + result = IsAnalysed() && + HasDirection(dir); + + // + return result; + } + + /** + * Check Analysis Has Bullish Trend or not ... + * + * @return ( bool ) + */ + bool HasBullishTrend() + { + // + bool result = false; + + // + result = HasTrend() && + IsSpecifiedBullish(dir); + + // + return result; + } + + /** + * Check Analysis Has Bearish Trend or not ... + * + * @return ( bool ) + */ + bool HasBearishTrend() + { + // + bool result = false; + + // + result = HasTrend() && + IsSpecifiedBearish(dir); + + // + return result; + } + + /** + * Check Market Has Support ... + * + * @return ( bool ) + */ + bool HasSupport() + { + // + bool result = false; + + // + result = + IsValid() && + HasPivots() && + IsAnalysed() && + NotEmpty(minorSupport) && + NotEmpty(majorSupport); + + // + return result; + } + + /** + * Check Market Has Resistance ... + * + * @return ( bool ) + */ + bool HasResistance() + { + // + bool result = false; + + // + result = + IsValid() && + HasPivots() && + IsAnalysed() && + NotEmpty(minorResistance) && + NotEmpty(majorResistance); + + // + return result; + } + + // + // Pivots ... + + /** + * Extract all Peaks from Exists Pivots ... + * + * @param dest: a Collection refrence to Hold Extracted Pivots ... + * + * @return ( int ) + */ + int ExtractPeaks(XPivot &dest[]) + { + // + int result = -1; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Do Extraction ... + result = ExtractPivots( + dest, + pivots, + X_PIVOT_TYPE_PEAK // + ); + + // + return result; + } + + /** + * Extract all Vales from Exists Pivots ... + * + * @param dest: a Collection refrence to Hold Extracted Pivots ... + * + * @return ( int ) + */ + int ExtractVales(XPivot &dest[]) + { + // + int result = -1; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Do Extraction ... + result = ExtractPivots( + dest, + pivots, + X_PIVOT_TYPE_VALE // + ); + + // + return result; + } + + /** + * Sort Pivots ... + * + * @param sortBy: ENUM_X_SORT_BY, Specified Sort Param ... + * @param sortDir: ENUM_X_DIRECTION, Specified Sort Direction ... + */ + void SortPivots( + ENUM_X_SORT_BY sortBy, + ENUM_X_DIRECTION sortDir // + ) + { + // + // Validate ... + bool has = IsValid() && + HasPivots(); + if (!has) + { + return; + } + + // + // Apply Sorting ... + Sort( + pivots, + sortBy, + sortDir // + ); + } + + // + // Boxing Tools ... + + /** + * Generate Support Box if Has Strong Supports ... + * + * @param box: a refrence XBoxZone to holds Generated result ... + * + * @return ( bool ) + */ + bool HasSupportBox(XBoxZone &box) + { + // + bool result = false; + + // + // Prepare ... + box.Clean(); + + // + // Validate ... + result = + IsValid() && + IsAnalysed(); + if (!result) + { + return result; + } + + // + box.to = toTime; + box.symbol = symbol; + box.period = period; + box.from = fromTime; + + // + box.upper = minorSupport; + box.lower = majorSupport; + box.dir = X_DIRECTION_BULLISH; + box.type = GetTag() + "_Support"; + + // + result = box.IsValid(); + if (!result) + { + box.Clean(); + } + + // + return result; + } + + /** + * Generate Resistance Box if Has Strong Resistance ... + * + * @param box: a refrence XBoxZone to holds Generated result ... + * + * @return ( bool ) + */ + bool HasResistanceBox(XBoxZone &box) + { + // + bool result = false; + + // + // Prepare ... + box.Clean(); + + // + // Validate ... + result = + IsValid() && + IsAnalysed(); + if (!result) + { + return result; + } + + // + box.to = toTime; + box.symbol = symbol; + box.period = period; + box.from = fromTime; + + // + box.upper = majorResistance; + box.lower = minorResistance; + box.dir = X_DIRECTION_BEARISH; + box.type = GetTag() + "_Resistance"; + + // + result = box.IsValid(); + if (!result) + { + box.Clean(); + } + + // + return result; + } + + // + // Detecting ... + + /** + * Check Two Model is Same or not ... + * + * @param item: Specified Model for Compare ... + * + * @return ( bool ) + */ + bool IsSameAs(XPivotAnalysis &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + IsSameMarketAs(item) && + name == item.name && + time == item.time; + + // + return result; + } + + /** + * Check Two Model Has Same Symbol or not ... + * + * @param item: Specified Model for Compare ... + * + * @return ( bool ) + */ + bool IsSameSymbolAs(XPivotAnalysis &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + symbol == item.symbol; + + // + return result; + } + + /** + * Check Two Model Has Same Period or not ... + * + * @param item: Specified Model for Compare ... + * + * @return ( bool ) + */ + bool IsSamePeriodAs(XPivotAnalysis &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + period == item.period; + + // + return result; + } + + /** + * Check Two Model Has Same Symbol/Period or not ... + * + * @param item: Specified Model for Compare ... + * + * @return ( bool ) + */ + bool IsSameMarketAs(XPivotAnalysis &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid() && + IsSameSymbolAs(item) && + IsSamePeriodAs(item); + + // + return result; + } + + // + // Logging ... + + /** + * Extract Specified Token of Struct ... + * + * @return ( string ) + */ + string GetTag() + { + return name + GetToken(this); + } + + /** + * Represent an String Unique Identifier for Chart Objects ... + * + * @return ( string ) + */ + string GetObjectID() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetTag() + "_" + symbol + "_" + ToXString(period); + + // + return result; + } + + /** + * Represent an String Unique Identifier for Upper Trend Chart Objects ... + * + * @return ( string ) + */ + string GetUpperObjectID() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetTag() + "_" + symbol + "_" + ToXString(period) + "_UPPER"; + + // + return result; + } + + /** + * Represent an String Unique Identifier for Lower Trend Chart Objects ... + * + * @return ( string ) + */ + string GetLowerObjectID() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetTag() + "_" + symbol + "_" + ToXString(period) + "_LOWER"; + + // + return result; + } + + /** + * Represent an String Unique Identifier for Support Box Chart Objects ... + * + * @return ( string ) + */ + string GetSupportBoxObjectID() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetTag() + "_" + symbol + "_" + ToXString(period) + "_SUPPORT"; + + // + return result; + } + + /** + * Represent an String Unique Identifier for Resistance BOX Chart Objects ... + * + * @return ( string ) + */ + string GetResistanceBoxObjectID() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetTag() + "_" + symbol + "_" + ToXString(period) + "_RESISTANCE"; + + // + return result; + } + + /** + * Represent as String ... + * + * @param spacer: string, How to Represent Spaces ... + * + * @return ( string ) + */ + string GetMessage(string spacer = NULL) + { + // + string result = ""; + + // + // Normalize Spacer ... + if (!IsSpecifiedValid(spacer)) + { + spacer = " "; + } + + // + // Validate ... + if (!IsValid()) + { + return result; + } + + // + result = + "==========================" + spacer + + GetTag() + ":" + spacer + + "==========================" + spacer + + "Symbol: " + symbol + spacer + + "Period: " + ToXString(period) + spacer + + (!HasTrend() + ? "" + : "Direction: " + ToXString(dir) + spacer) + + "Time: " + ToXString(time) + spacer; + + // + return result; + } + + // +}; + +/** + * a Model to Describe Specified Bar Pattern's Analysis ... + **/ +struct XPatternAnalysis +{ + // + // Props ... + XOHCL bar; // Specified Bar ... + XBoxZone ob; // OrderBlock if Exists ... + XBoxZone fvg; // Fair Value Gap if Exists ... + datetime time; // Analysis Time ... + XOHCL flagSwing; // Flag Patterns Swing Bar if Exists ... + XBoxZone support; // Bar's Support if Exists ... + XBoxZone resistance; // Bar's Resistance if Exists ... + ENUM_X_BAR_PATTERN patterns[]; // All Bars Exists Patterns ... + ENUM_X_DIRECTION patternsDir[]; // Each Exists Patterns Directions ... + + // + // Constructor ... + XPatternAnalysis() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup Model ... + */ + void Clean() + { + // + ob.Clean(); + bar.Clean(); + fvg.Clean(); + time = NULL; + support.Clean(); + XClean(patterns); + flagSwing.Clean(); + resistance.Clean(); + XClean(patternsDir); + + // + ZeroMemory(this); + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = bar.IsValid() && + IsXValid(time); + + // + return result; + } + + // + // Pattern Actions ... + + /** + * Count Directional Patterns ... + * + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( int ) + */ + int Count( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + int result = 0; + + // + // Validate ... + bool has = IsValid() && + HasChild(patternsDir); + if (!has) + { + return result; + } + + // + int count = ArraySize(patternsDir); + if (!HasDirection(forDir)) + { + // + result = count; + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + has = forDir == patternsDir[i]; + if (has) + { + result++; + } + } + + // + return result; + } + + // + // Detectors ... + + bool IsHigh() + { + // + bool result = false; + + // + result = HasPattern(X_BAR_PATTERN_HIGH); + + // + return result; + } + + bool IsLow() + { + // + bool result = false; + + // + result = HasPattern(X_BAR_PATTERN_LOW); + + // + return result; + } + + bool IsSupport() + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_SUPPORT // + ); + + // + return result; + } + + bool IsResistance() + { + // + bool result = false; + + // + result = HasPattern(X_BAR_PATTERN_RESISTANCE); + + // + return result; + } + + bool IsMomentum( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_MOMENTUM, + forDir // + ); + + // + return result; + } + + bool IsEngulfed( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_ENGULFED, + forDir // + ); + + // + return result; + } + + bool IsTrueGaped( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_TRUE_GAPED, + forDir // + ); + + // + return result; + } + + bool IsPinned( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_PINNED, + forDir // + ); + + // + return result; + } + + bool IsStar( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_STAR, + forDir // + ); + + // + return result; + } + + bool IsPiercing( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_PIERCING, + forDir // + ); + + // + return result; + } + + bool IsRising( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_RISING, + forDir // + ); + + // + return result; + } + + bool IsFlag( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_FLAG, + forDir // + ); + + // + return result; + } + + bool IsSignalKey( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_SIGNALKEY, + forDir // + ); + + // + return result; + } + + bool IsOB( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_OB, + forDir // + ); + + // + return result; + } + + bool IsFVG( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = HasPattern( + X_BAR_PATTERN_FVG, + forDir // + ); + + // + return result; + } + + // + // Getters ... + + bool GetLow( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_LOW; + ENUM_X_DIRECTION _patternDir = X_DIRECTION_BULLISH; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetHigh( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_HIGH; + ENUM_X_DIRECTION _patternDir = X_DIRECTION_BEARISH; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetSupport( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_SUPPORT; + ENUM_X_DIRECTION _patternDir = X_DIRECTION_BULLISH; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetResistance( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_RESISTANCE; + ENUM_X_DIRECTION _patternDir = X_DIRECTION_BEARISH; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetOB( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_OB; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetFVG( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_FVG; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetMomentum( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_MOMENTUM; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetEngulfed( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_ENGULFED; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetPinned( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_PINNED; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetTrueGaped( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_TRUE_GAPED; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetStar( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_STAR; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetFlag( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_FLAG; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetRising( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_RISING; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetPiercing( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_PIERCING; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + bool GetSignalKey( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + ENUM_X_BAR_PATTERN _pattern = X_BAR_PATTERN_SIGNALKEY; + + // + return GetPattern( + _bar, + _pivot, + _zone, + _pattern, + _patternDir // + ); + } + + // + // Common Tools ... + + /** + * Add Specified Patterns to Model ... + * + * @param pattern: ENUM_X_BAR_PATTERN, Specified Pattern ... + * @param patternDir: ENUM_X_DIRECTION, Specified Pattern Direction ... + */ + void AddPattern( + ENUM_X_BAR_PATTERN pattern, + ENUM_X_DIRECTION patternDir // + ) + { + // + bool has = IsXValid(pattern) && + HasDirection(patternDir); + if (!has) + { + return; + } + + // + Add( + pattern, + patterns // + ); + + // + Add( + patternDir, + patternsDir // + ); + } + + /** + * Check Model Has Specified Pattern or not ... + * + * @param pattern: ENUM_X_BAR_PATTERN, Specified Pattern ... + * @param patternDir: ENUM_X_DIRECTION, Specified Pattern Direction ... + * + * @return ( bool ) + */ + bool HasPattern( + ENUM_X_BAR_PATTERN pattern, + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = Contains( + pattern, + patterns // + ); + if (!result) + { + return result; + } + + // + if (HasDirection(forDir)) + { + // + int idx = FindIndex( + pattern, + patterns // + ); + result = + IsValidIndex(idx) && + forDir == patternsDir[idx]; + } + + // + return result; + } + + /** + * Get Specified Pattern if Exists ... + * + * @param _bar: XOHCL, Patterns Bar ... + * @param _pivot: XPivot, Patterns Pivot ... + * @param _zone: XBoxZone, Patterns Box ... + * @param _pattern: ENUM_X_BAR_PATTERN, Specified Pattern ... + * @param _patternDir: ENUM_X_DIRECTION, Specified Pattern Direction ... + * @param _peakPriceType: ENUM_X_PRICE, Specified Peak Price Type ... + * @param _valePriceType: ENUM_X_PRICE, Specified Vale Price Type ... + * @param _toTime: datetime, Specified Time to Update Pivot and Zones ... + * + * @return ( bool ) + */ + bool GetPattern( + XOHCL &_bar, + XPivot &_pivot, + XBoxZone &_zone, + ENUM_X_BAR_PATTERN _pattern, + ENUM_X_DIRECTION _patternDir = X_DIRECTION_NONE, + ENUM_X_PRICE _peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE _valePriceType = X_PRICE_LOW, + datetime _toTime = NULL // + ) + { + // + bool result = false; + + // + // Prepare ... + _bar.Clean(); + _zone.Clean(); + _pivot.Clean(); + + // + // Normalize ... + if (!IsXValid(_peakPriceType)) + { + _peakPriceType = X_PRICE_HIGH; + } + if (!IsXValid(_valePriceType)) + { + _valePriceType = X_PRICE_LOW; + } + _toTime = NormalizeTime(_toTime); + + // + // Validate ... + result = IsValid() && + HasChild(patterns) && + IsXValid(_peakPriceType) && + IsXValid(_valePriceType) && + HasPattern(_pattern, _patternDir); + if (!result) + { + return result; + } + + // + // Find Pattern Index ... + int index = FindIndex(_pattern, patterns); + result = IsValidIndex(index); + if (!result) + { + return result; + } + + // + // Fill Common Patterns Data ... + _bar = bar; + result = ToPivot( + _bar, + _pivot, + _patternDir, + _pattern, + _peakPriceType, + _valePriceType // + ); + result = result && + ToBox( + _bar, + _zone, + _patternDir, + _pattern, + _peakPriceType, + _valePriceType // + ); + if (result) + { + _zone.to = _toTime; + } + + // + // Use Custom Data if Pattern Staisfied ... + if (result) + { + // + // OB ... + if (_pattern == X_BAR_PATTERN_OB) + { + // + _bar.Clean(); + _zone.Clean(); + _pivot.Clean(); + + // + // Result Preparation ... + result = ob.IsValid() && + ob.dir == _patternDir; + if (result) + { + // + _zone = ob; + result = _zone.FromBar(_bar); + if (result) + { + // + result = ToPivot( + _bar, + _pivot, + _patternDir, + _pattern, + _peakPriceType, + _valePriceType // + ); + } + } + } + // + // FVG ... + else if (_pattern == X_BAR_PATTERN_FVG) + { + // + _bar.Clean(); + _zone.Clean(); + _pivot.Clean(); + + // + // Result Preparation ... + result = fvg.IsValid() && + fvg.dir == _patternDir; + if (result) + { + // + _zone = fvg; + result = _zone.FromBar(_bar); + if (result) + { + // + result = ToPivot( + _bar, + _pivot, + _patternDir, + _pattern, + _peakPriceType, + _valePriceType // + ); + } + } + } + // + // Support ... + else if (_pattern == X_BAR_PATTERN_SUPPORT) + { + // + _bar.Clean(); + _zone.Clean(); + _pivot.Clean(); + + // + // Result Preparation ... + result = support.IsValid(); + if (result) + { + // + _zone = support; + result = _zone.AtBar(_bar); + if (result) + { + // + result = ToPivot( + _bar, + _pivot, + _patternDir, + _pattern, + _peakPriceType, + _valePriceType // + ); + } + } + } + // + // Resistance ... + else if (_pattern == X_BAR_PATTERN_RESISTANCE) + { + // + _bar.Clean(); + _zone.Clean(); + _pivot.Clean(); + + // + // Result Preparation ... + result = resistance.IsValid(); + if (result) + { + // + _zone = resistance; + result = _zone.AtBar(_bar); + if (result) + { + // + result = ToPivot( + _bar, + _pivot, + _patternDir, + _pattern, + _peakPriceType, + _valePriceType // + ); + } + } + } + } + + // + // Cleanup Resources ... + if (!result) + { + // + _bar.Clean(); + _zone.Clean(); + _pivot.Clean(); + } + + // + return result; + } + + /** + * Extract All Exists Patterns Pivots ... + * + * @param dest: XPivot, collection reference to holds Extracted Patterns ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction of Extractions ... + * + * @return ( int ) + */ + int GetPatterns( + XPivot &dest[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Validate ... + bool has = IsValid() && + HasChild(patterns); + if (!has) + { + return result; + } + + // + // Do ... + XOHCL iBar; + XPivot iPivot; + XBoxZone iZone; + int count = ArraySize(patterns); + for (int i = 0; i < count; i++) + { + // + has = GetPattern(iBar, iPivot, iZone, patterns[i], forDir); + if (has) + { + AddIfNotExists(iPivot, dest); + } + } + + // + result = ArraySize(dest); + + // + // Cleanup ... + iBar.Clean(); + iZone.Clean(); + iPivot.Clean(); + + // + return result; + } + + /** + * Extract All Exists Patterns Pivots ... + * + * @param dest: XBoxZone, collection reference to holds Extracted Patterns ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction of Extractions ... + * + * @return ( int ) + */ + int GetPatterns( + XBoxZone &dest[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Validate ... + bool has = IsValid() && + HasChild(patterns); + if (!has) + { + return result; + } + + // + // Do ... + XOHCL iBar; + XPivot iPivot; + XBoxZone iZone; + int count = ArraySize(patterns); + for (int i = 0; i < count; i++) + { + // + has = GetPattern(iBar, iPivot, iZone, patterns[i], forDir); + if (has) + { + AddIfNotExists(iZone, dest); + } + } + + // + result = ArraySize(dest); + + // + // Cleanup ... + iBar.Clean(); + iZone.Clean(); + iPivot.Clean(); + + // + return result; + } + + /** + * Extract All Exists Patterns Pivots ... + * + * @param dest: XPivot, collection reference to holds Extracted Patterns ... + * @param zones: XBoxZone, collection reference to holds Extracted Patterns ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction of Extractions ... + * + * @return ( int ) + */ + int GetPatterns( + XPivot &dest[], + XBoxZone &zones[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + XClean(zones); + + // + // Validate ... + bool has = IsValid() && + HasChild(patterns); + if (!has) + { + return result; + } + + // + // Do ... + XOHCL iBar; + XPivot iPivot; + XBoxZone iZone; + int count = ArraySize(patterns); + for (int i = 0; i < count; i++) + { + // + has = GetPattern(iBar, iPivot, iZone, patterns[i], forDir); + if (has) + { + // + AddIfNotExists(iPivot, dest); + AddIfNotExists(iZone, zones); + } + } + + // + result = ArraySize(dest); + + // + // Cleanup ... + iBar.Clean(); + iZone.Clean(); + iPivot.Clean(); + + // + return result; + } + + // +}; + +struct XPatternAnalysisConfig +{ + // + // Props ... + + // + // PV ... + int pvValidationLength; + ENUM_X_PRICE peakPriceType; + ENUM_X_PRICE valePriceType; + + // + // Momentum ... + int momentumBarValidationLength; + double momentumBarApprovedMultiplier; + + // + // TrueGap ... + double trueGapApprovedStrength; + + // + // Pin ... + double pinBarShadowApprovedMultiplier; + double pinBarRangeMultiplier; + bool pinBarForceDirection; + + // + // Flag ... + int flagPatternPullbackLength; + + // + // FVG ... + bool fvgForceType; + + // + // OB ... + bool obForceTwoBar; + + // + // Support and Resistance ... + int supportAndResistanceValidationLength; + int supportAndResistanceLoopbackLength; + + // + ENUM_X_DIRECTION allowedDirs[]; + ENUM_X_BAR_PATTERN allowedPatterns[]; + + // + // Constructor ... + XPatternAnalysisConfig() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + // PV ... + pvValidationLength = 0; + peakPriceType = X_PRICE_NONE; + valePriceType = X_PRICE_NONE; + + // + // Momentum ... + momentumBarValidationLength = 0; + momentumBarApprovedMultiplier = 0; + + // + // TrueGap ... + trueGapApprovedStrength = 0; + + // + // Pin ... + pinBarShadowApprovedMultiplier = 0; + pinBarRangeMultiplier = 0; + pinBarForceDirection = false; + + // + // Flag ... + flagPatternPullbackLength = 0; + + // + // FVG ... + fvgForceType = false; + + // + // OB ... + obForceTwoBar = false; + + // + // Support and Resistance ... + supportAndResistanceValidationLength = 0; + supportAndResistanceLoopbackLength = 0; + + // + XClean(allowedDirs); + XClean(allowedPatterns); + + // + ZeroMemory(this); + } + + /** + * Default Configurations ... + */ + void Default() + { + // + // PV ... + pvValidationLength = 5; + peakPriceType = X_PRICE_HIGH; + valePriceType = X_PRICE_LOW; + + // + // Momentum ... + momentumBarValidationLength = 3; + momentumBarApprovedMultiplier = 3; + + // + // TrueGap ... + trueGapApprovedStrength = 1; + + // + // Pin ... + pinBarShadowApprovedMultiplier = 3; + pinBarRangeMultiplier = 4; + pinBarForceDirection = false; + + // + // Flag ... + flagPatternPullbackLength = 3; + + // + // FVG ... + fvgForceType = false; + + // + // OB ... + obForceTwoBar = false; + + // + // Support and Resistance ... + supportAndResistanceValidationLength = 21; + supportAndResistanceLoopbackLength = 50; + } + + // + // Permissions ... + + /** + * Check Specified Patterns Detection is Allowed or not ... + * + * @param pattern: ENUM_X_BAR_PATTERN, Specified Pattern to Detect ... + * @param patternDir: ENUM_X_DIRECTION, which Pattern Direction to Detect ... + * + * @return ( bool ) + */ + bool CanDetect( + ENUM_X_BAR_PATTERN pattern, + ENUM_X_DIRECTION patternDir = X_DIRECTION_NONE // + ) + { + // + bool result = false; + + // + // Validate Pattern and + // Check Pattern Exists ... + result = IsXValid(pattern) && + HasChild(allowedPatterns) && + Contains(pattern, allowedPatterns); + if (!result) + { + return result; + } + + // + // Now Check Direction ... + int index = FindIndex(pattern, allowedPatterns); + result = IsValidIndex(index) && + HasChild(allowedDirs) && + (!HasDirection(patternDir) + ? !HasDirection(allowedDirs[index]) + : (!HasDirection(allowedDirs[index]) || + patternDir == allowedDirs[index])); + + // + return result; + } + + // + // Collection Manipulations ... + + /** + * Remove all Allowed Patterns and Directions ... + */ + void CleanPatterns() + { + // + XClean(allowedDirs); + XClean(allowedPatterns); + } + + /** + * Full Detect Patterns ... + * + * @param forDir: ENUM_X_DIRECTION, which Pattern Direction to Detect ... + */ + void FullPattern( + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // + ) + { + // + int count = GetAllBarPatters(allowedPatterns); + for (int i = 0; i < count; i++) + { + // + Add( + forDir, + allowedDirs // + ); + } + } + + /** + * Add Specified Pattern to Detecte ... + * + * @param pattern: ENUM_X_BAR_PATTERN, Specified Pattern to Detect ... + * @param patternDir: ENUM_X_DIRECTION, which Pattern Direction to Detect ... + */ + void AddPattern( + ENUM_X_BAR_PATTERN pattern, + ENUM_X_DIRECTION patternDir = X_DIRECTION_NONE // + ) + { + // + bool has = IsXValid(pattern); + if (!has) + { + return; + } + + // + Add( + pattern, + allowedPatterns // + ); + + // + Add( + patternDir, + allowedDirs // + ); + } + + // +}; + +// +// Anaysis Draw Config Models ... + +struct XPivotAnalysisDrawConfig +{ + // + // Props ... + + // + // Drawing Flags ... + bool drawSupport; + bool drawResistance; + + // + bool drawPeakTrend; + bool drawValeTrend; + bool rayLeftTrends; + bool rayRightTrends; + + // + bool drawPivots; + + // + // Drawing Configs ... + XPOIDrawConfig drawConfig; + + // + // Constructor ... + XPivotAnalysisDrawConfig() + { + Clean(); + } + + // + // Tools ... + + /** + * This function fulfills the will of the developer + */ + void Clean() + { + // + // Drawing Flags ... + + // + drawPivots = false; + drawSupport = false; + drawPeakTrend = false; + drawValeTrend = false; + rayLeftTrends = false; + rayRightTrends = false; + drawResistance = false; + + // + // Drawing Configs ... + drawConfig.Clean(); + + // + ZeroMemory(this); + } + + /** + * Default Configurations ... + */ + void Default() + { + // + // Drawing Flags ... + + // + drawPivots = false; + drawSupport = true; + drawPeakTrend = false; + drawValeTrend = false; + rayLeftTrends = true; + rayRightTrends = true; + drawResistance = true; + + // + // Drawing Configs ... + drawConfig.Default(); + } + + /** + * No Draw Abilioty ... + */ + void Off() + { + // + drawPivots = false; + drawSupport = false; + drawPeakTrend = false; + drawValeTrend = false; + drawResistance = false; + } + + /** + * Full Draw Abilioty ... + */ + void Full() + { + // + drawPivots = true; + drawSupport = true; + drawPeakTrend = true; + drawValeTrend = true; + drawResistance = true; + } + + // +}; + +struct XPatternAnalysisDrawConfig +{ + // + // Props ... + + // + // Patterns ... + + // + ENUM_X_BAR_PATTERN allowedDraws[]; // Allowed Draw Patterns + ENUM_X_BAR_PATTERN allowedDrawZones[]; // Allowed Draw Pattern Zones + ENUM_X_BAR_PATTERN allowedDrawPivots[]; // Allowed Draw Pattern Pivots + + // + XPOIDrawConfig drawConfig; + + // + // Constructor ... + XPatternAnalysisDrawConfig() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + // Drawing Configs ... + drawConfig.Clean(); + + // + XClean(allowedDraws); + XClean(allowedDrawZones); + XClean(allowedDrawPivots); + } + + /** + * Default Drawing Config ... + */ + void Default() + { + // + // Drawing Configs ... + drawConfig.Default(); + + // + Full(); + + // + // Remove Unused From Zones ... + Remove(X_BAR_PATTERN_PINNED, allowedDrawZones); + Remove(X_BAR_PATTERN_MOMENTUM, allowedDrawZones); + Remove(X_BAR_PATTERN_ENGULFED, allowedDrawZones); + Remove(X_BAR_PATTERN_TRUE_GAPED, allowedDrawZones); + + // + // Remove Unused From Pivots ... + Remove(X_BAR_PATTERN_OB, allowedDrawPivots); + Remove(X_BAR_PATTERN_FVG, allowedDrawPivots); + Remove(X_BAR_PATTERN_SUPPORT, allowedDrawPivots); + Remove(X_BAR_PATTERN_RESISTANCE, allowedDrawPivots); + } + + /** + * No Draw Abilioty ... + */ + void Off() + { + // + XClean(allowedDraws); + XClean(allowedDrawZones); + XClean(allowedDrawPivots); + } + + /** + * Full Draw Abilioty ... + */ + void Full() + { + // + GetAllBarPatters(allowedDraws); + GetAllBarPatters(allowedDrawZones); + GetAllBarPatters(allowedDrawPivots); + } + + // + // Checkers ... + + /** + * Check Can Draw Specified Pattern ... + * + * @param pattern: ENUM_X_BAR_PATTERN, Specified Pattern ... + * + * @return ( bool ) + */ + bool CanDraw(ENUM_X_BAR_PATTERN pattern) + { + // + bool result = false; + + // + result = HasChild(allowedDraws) && + Contains(pattern, allowedDraws); + + // + return result; + } + + /** + * Check Can Draw Specified Pattern's Zone ... + * + * @param pattern: ENUM_X_BAR_PATTERN, Specified Pattern ... + * + * @return ( bool ) + */ + bool CanDrawZone(ENUM_X_BAR_PATTERN pattern) + { + // + bool result = false; + + // + result = + CanDraw(pattern) && + HasChild(allowedDrawZones) && + Contains(pattern, allowedDrawZones); + + // + return result; + } + + /** + * Check Can Draw Specified Pattern's Pivot ... + * + * @param pattern: ENUM_X_BAR_PATTERN, Specified Pattern ... + * + * @return ( bool ) + */ + bool CanDrawPivot(ENUM_X_BAR_PATTERN pattern) + { + // + bool result = false; + + // + result = + CanDraw(pattern) && + HasChild(allowedDrawPivots) && + Contains(pattern, allowedDrawPivots); + + // + return result; + } +}; + +// +// Extensions ... + +bool FindByTime( + int &index, + datetime time, + XPatternAnalysis &source[] // +) +{ + // + bool result = false; + + // + // Prepare ... + index = -1; + + // + // Validate ... + result = IsXValid(time) && + HasChild(source); + if (!result) + { + return result; + } + + // + // Do ... + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + result = source[i].bar.time == time; + if (result) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; +} + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.x-poi.extensions.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XPOILib +// Description: All models related to POIs ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright `023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Libraries/x-saherelm.x-ohcl.lib.mq5" +#include "../Libraries/x-saherelm.x-poi.lib.mq5" + +// +// Extensions ... +//+------------------------------------------------------------------+ +//| Oldest Detection | +//+------------------------------------------------------------------+ +/** + * Get Oldest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetOldest( + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + !selected.IsValid() + ? true + : selected.from > source[i].from; + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Oldest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( int ) + */ +int GetOldestByDir( + XBoxZone &source[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + (!HasDirection(forDir) + ? true + : forDir == source[i].dir) && + (!selected.IsValid() + ? true + : selected.from > source[i].from); + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Oldest Index of Specified Collection ... + * + * @param bar: XOHCL, Specified Bar ... + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetOldestByBar( + XOHCL &bar, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + if (!bar.IsValid()) + { + return result; + } + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool isBoxValidForBar = IsBoxPlaceValidForBar(bar, source[i]); + if (!isBoxValidForBar) + { + continue; + } + + // + bool canSet = + !selected.IsValid() + ? true + : selected.from > source[i].from; + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Oldest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param type: ENUM_X_PIVOT_TYPE, Specified Points Type ... + * + * @return ( int ) + */ +int GetOldest( + XPivot &source[], + ENUM_X_PIVOT_TYPE type = X_PIVOT_TYPE_NONE // +) +{ + // + int result = -1; + + // + // Validate ... + if (!HasChild(source)) + { + return result; + } + + // + bool has = false; + XPivot iPoint; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + // Passed Type ... + has = !IsXValid(type) + ? true + : type == source[i].type; + + // + // Check Can Assign ... + has = + has && + (!iPoint.IsValid() || + (iPoint.IsValid() && + source[i].GetAge() > iPoint.GetAge())); + if (has) + { + // + result = i; + iPoint = source[i]; + } + } + + // + // Validate Result ... + has = + iPoint.IsValid() && + IsValidIndex(result); + if (!has) + { + // + result = -1; + iPoint.Clean(); + return result; + } + + // + iPoint.Clean(); + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Youngest Detection | +//+------------------------------------------------------------------+ +/** + * Get Youngest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetYoungest( + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + !selected.IsValid() + ? true + : selected.from < source[i].from; + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Youngest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( int ) + */ +int GetYoungestByDir( + XBoxZone &source[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + (!HasDirection(forDir) + ? true + : forDir == source[i].dir) && + (!selected.IsValid() + ? true + : selected.from < source[i].from); + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Youngest Index of Specified Collection ... + * + * @param bar: XOHCL, Specified Bar ... + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetYoungestByBar( + XOHCL &bar, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + if (!bar.IsValid()) + { + return result; + } + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool isBoxValidForBar = IsBoxPlaceValidForBar(bar, source[i]); + if (!isBoxValidForBar) + { + continue; + } + + // + bool canSet = + !selected.IsValid() + ? true + : selected.from < source[i].from; + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Youngest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param type: ENUM_X_PIVOT_TYPE, Specified Points Type ... + * + * @return ( int ) + */ +int GetYoungest( + XPivot &source[], + ENUM_X_PIVOT_TYPE type = X_PIVOT_TYPE_NONE // +) +{ + // + int result = -1; + + // + // Validate ... + if (!HasChild(source)) + { + return result; + } + + // + bool has = false; + XPivot iPoint; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + // Passed Type ... + has = !IsXValid(type) + ? true + : type == source[i].type; + + // + // Check Can Assign ... + has = + has && + (!iPoint.IsValid() || + (iPoint.IsValid() && + source[i].GetAge() < iPoint.GetAge())); + if (has) + { + // + result = i; + iPoint = source[i]; + } + } + + // + // Validate Result ... + has = + iPoint.IsValid() && + IsValidIndex(result); + if (!has) + { + // + result = -1; + iPoint.Clean(); + return result; + } + + // + iPoint.Clean(); + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Highest Detection | +//+------------------------------------------------------------------+ +/** + * Get Highest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetHighest( + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + !selected.IsValid() + ? true + : selected.upper < source[i].upper; + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Highest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( int ) + */ +int GetHighestByDir( + XBoxZone &source[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + bool canSet = + (!HasDirection(forDir) + ? true + : forDir == source[i].dir) && + (!selected.IsValid() + ? true + : selected.upper < source[i].upper); + if (canSet) + { + // + result = i; + selected = source[i]; + } + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Highest Index of Specified Collection ... + * + * @param bar: XOHCL, Specified Bar ... + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetHighestByBar( + XOHCL &bar, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + if (!bar.IsValid()) + { + return result; + } + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + bool isBoxValidForBar = IsBoxPlaceValidForBar(bar, iBox); + if (!isBoxValidForBar) + { + // + iBox.Clean(); + + // + continue; + } + + // + bool canSet = + !selected.IsValid() + ? true + : selected.upper < iBox.upper; + if (canSet) + { + // + result = i; + selected = iBox; + } + + // + iBox.Clean(); + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Highest Bar Price Index of Specified Collection ... + * + * @param source: reference collection, Provides Data Source ... + * + * @return ( int ) + */ +int GetHighestBarPrice( + XOHCL &source[], + ENUM_X_PRICE priceType // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = HasChild(source) && + IsXValid(priceType); + if (!has) + { + return result; + } + + // + double price = EMPTY_VALUE; + double selected = EMPTY_VALUE; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + price = source[i].GetPrice(priceType); + has = !NotEmptyZero(selected) + ? true + : price > selected; + if (has) + { + // + result = i; + selected = price; + } + } + + // + return result; +} + +/** + * Get Highest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param type: ENUM_X_PIVOT_TYPE, Specified Points Type ... + * + * @return ( int ) + */ +int GetHighest( + XPivot &source[], + ENUM_X_PIVOT_TYPE type = X_PIVOT_TYPE_NONE // +) +{ + // + int result = -1; + + // + // Validate ... + if (!HasChild(source)) + { + return result; + } + + // + bool has = false; + XPivot iPoint; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + // Passed Type ... + has = !IsXValid(type) + ? true + : type == source[i].type; + + // + // Check Can Assign ... + has = + has && + (!iPoint.IsValid() || + (iPoint.IsValid() && + source[i].value > iPoint.value)); + if (has) + { + // + result = i; + iPoint = source[i]; + } + } + + // + // Validate Result ... + has = + iPoint.IsValid() && + IsValidIndex(result); + if (!has) + { + // + result = -1; + iPoint.Clean(); + return result; + } + + // + iPoint.Clean(); + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Loest Detection | +//+------------------------------------------------------------------+ +/** + * Get Lowest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetLowest( + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + bool canSet = + !selected.IsValid() + ? true + : selected.lower > iBox.lower; + if (canSet) + { + // + result = i; + selected = iBox; + } + + // + iBox.Clean(); + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Lowest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( int ) + */ +int GetLowestByDir( + XBoxZone &source[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = -1; + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + bool canSet = + (!HasDirection(forDir) + ? true + : forDir == source[i].dir) && + (!selected.IsValid() + ? true + : selected.lower > iBox.lower); + if (canSet) + { + // + result = i; + selected = iBox; + } + + // + iBox.Clean(); + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Lowest Index of Specified Collection ... + * + * @param bar: XOHCL, Specified Bar ... + * @param source: Specified Collection ... + * + * @return ( int ) + */ +int GetLowestByBar( + XOHCL &bar, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + if (!bar.IsValid()) + { + return result; + } + + // + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XBoxZone selected; + for (int i = 0; i < count; i++) + { + // + XBoxZone iBox = source[i]; + + // + bool isBoxValidForBar = IsBoxPlaceValidForBar(bar, iBox); + if (!isBoxValidForBar) + { + // + iBox.Clean(); + + // + continue; + } + + // + bool canSet = + !selected.IsValid() + ? true + : selected.lower > iBox.lower; + if (canSet) + { + // + result = i; + selected = iBox; + } + + // + iBox.Clean(); + } + + // + selected.Clean(); + + // + return result; +} + +/** + * Get Lowest Bar Price Index of Specified Collection ... + * + * @param source: reference collection, Provides Data Source ... + * + * @return ( int ) + */ +int GetLowestBarPrice( + XOHCL &source[], + ENUM_X_PRICE priceType // +) +{ + // + int result = -1; + + // + // Validate ... + bool has = HasChild(source) && + IsXValid(priceType); + if (!has) + { + return result; + } + + // + double price = EMPTY_VALUE; + double selected = EMPTY_VALUE; + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + price = source[i].GetPrice(priceType); + has = !NotEmptyZero(selected) + ? true + : price < selected; + if (has) + { + // + result = i; + selected = price; + } + } + + // + return result; +} + +/** + * Get Lowest Index of Specified Collection ... + * + * @param source: Specified Collection ... + * @param type: ENUM_X_PIVOT_TYPE, Specified Points Type ... + * + * @return ( int ) + */ +int GetLowest( + XPivot &items[], + ENUM_X_PIVOT_TYPE type = X_PIVOT_TYPE_NONE // +) +{ + // + int result = -1; + + // + // Validate ... + if (!HasChild(items)) + { + return result; + } + + // + bool has = false; + XPivot iPoint; + int count = ArraySize(items); + for (int i = 0; i < count; i++) + { + // + // Passed Type ... + has = !IsXValid(type) + ? true + : type == items[i].type; + + // + // Check Can Assign ... + has = + has && + (!iPoint.IsValid() || + (iPoint.IsValid() && + items[i].value < iPoint.value)); + if (has) + { + // + result = i; + iPoint = items[i]; + } + } + + // + // Validate Result ... + has = + iPoint.IsValid() && + IsValidIndex(result); + if (!has) + { + // + result = -1; + iPoint.Clean(); + return result; + } + + // + iPoint.Clean(); + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Box | +//+------------------------------------------------------------------+ +/** + * Extract all items which appears Before Specified Time ... + * + * @param _time: Specified Time ... + * @param dest: refrence collection to hold result ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetBeforeItems( + datetime _time, + XBoxZone &dest[], + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Validate ... + int count = ArraySize(source); + bool has = HasChild(source) && + IsSpecifiedValid(_time); + if (!has) + { + return result; + } + + // + // Loop through Items ... + for (int i = 0; i < count; i++) + { + // + has = source[i].from < _time; + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Extract all items which appears After Specified Time ... + * + * @param _time: Specified Time ... + * @param dest: refrence collection to hold result ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetAfterItems( + datetime _time, + XBoxZone &dest[], + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Validate ... + int count = ArraySize(source); + bool has = HasChild(source) && + IsSpecifiedValid(_time); + if (!has) + { + return result; + } + + // + // Loop through Items ... + for (int i = 0; i < count; i++) + { + // + has = source[i].from > _time; + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Extract all items which appears Above Specified Value ... + * + * @param _value: Specified Value ... + * @param dest: refrence collection to hold result ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetAboveItems( + double _value, + XBoxZone &dest[], + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Validate ... + int count = ArraySize(source); + bool has = HasChild(source) && + NotEmptyZero(_value); + if (!has) + { + return result; + } + + // + // Loop through Items ... + for (int i = 0; i < count; i++) + { + // + has = source[i].lower > _value; + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Extract all items which appears Below Specified Value ... + * + * @param _value: Specified Value ... + * @param dest: refrence collection to hold result ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetBelowItems( + double _value, + XBoxZone &dest[], + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Validate ... + int count = ArraySize(source); + bool has = HasChild(source) && + NotEmptyZero(_value); + if (!has) + { + return result; + } + + // + // Loop through Items ... + for (int i = 0; i < count; i++) + { + // + has = source[i].upper < _value; + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Get Oldest Item Index of all items which appears Before Specified Value ... + * + * @param _time: Specified Time ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetOldestBefore( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetBeforeItems( + _time, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetOldest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Oldest Item Index of all items which appears After Specified Value ... + * + * @param _time: Specified Time ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetOldestAfter( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetAfterItems( + _time, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetOldest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Oldest Item Index of all items which appears Above Specified Value ... + * + * @param _value: Specified Value ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetOldestAbove( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetAboveItems( + _value, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetOldest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Oldest Item Index of all items which appears Below Specified Value ... + * + * @param _value: Specified Value ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetOldestBelow( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetBelowItems( + _value, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetOldest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Youngest Item Index of all items which appears Before Specified Value ... + * + * @param _time: Specified Time ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetYoungestBefore( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetBeforeItems( + _time, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetYoungest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Youngest Item Index of all items which appears After Specified Value ... + * + * @param _time: Specified Time ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetYoungestAfter( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetAfterItems( + _time, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetYoungest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Youngest Item Index of all items which appears Above Specified Value ... + * + * @param _value: Specified Value ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetYoungestAbove( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetAboveItems( + _value, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetYoungest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Youngest Item Index of all items which appears Below Specified Value ... + * + * @param _value: Specified Value ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetYoungestBelow( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetBelowItems( + _value, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetYoungest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Highest Item Index of all items which appears Before Specified Value ... + * + * @param _time: Specified Time ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetHighestBefore( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetBeforeItems( + _time, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetHighest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Highest Item Index of all items which appears After Specified Value ... + * + * @param _time: Specified Time ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetHighestAfter( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetAfterItems( + _time, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetHighest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Highest Item Index of all items which appears Above Specified Value ... + * + * @param _value: Specified Value ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetHighestAbove( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetAboveItems( + _value, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetHighest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Highest Item Index of all items which appears Below Specified Value ... + * + * @param _value: Specified Value ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetHighestBelow( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetBelowItems( + _value, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetHighest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Lowest Item Index of all items which appears Before Specified Value ... + * + * @param _time: Specified Time ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetLowestBefore( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetBeforeItems( + _time, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetLowest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Lowest Item Index of all items which appears After Specified Value ... + * + * @param _time: Specified Time ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetLowestAfter( + datetime _time, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetAfterItems( + _time, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetLowest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Lowest Item Index of all items which appears Above Specified Value ... + * + * @param _value: Specified Value ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetLowestAbove( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetAboveItems( + _value, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetLowest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Get Lowest Item Index of all items which appears Below Specified Value ... + * + * @param _value: Specified Value ... + * @param source: refrence collection to provides data source ... + * + * @return ( int ) + */ +int GetLowestBelow( + double _value, + XBoxZone &source[] // +) +{ + // + int result = -1; + + // + XBoxZone tmps[]; + int tmpsCount = GetBelowItems( + _value, + tmps, // Dest ... + source // Source ... + ); + bool has = IsValidSize(tmpsCount); + int idx = GetLowest(tmps); + has = + has && + IsValidIndex(idx) && + FindIndex( + result, + tmps[idx], + source // + ); + SpecifiedClean(tmps); + + // + return result; +} + +/** + * Validate an Item Strength ... + * + * @param item: Specified Item for Validating ... + * @param minAllowedStrength: int, Minimum required Strength in Point ... + * + * @return ( bool ) + */ +bool ValidateStrength( + XBoxZone &item, + int minAllowedStrength = 0 // +) +{ + // + bool result = false; + + // + // Normalize ... + minAllowedStrength = NormalizeInt(minAllowedStrength, 0); + + // + // Validate ... + result = item.IsValid(); + if (!result) + { + return result; + } + + // + // If doent provide Specified Strength Validate Zone ... + result = minAllowedStrength <= 0; + if (result) + { + return result; + } + + // + double points = GetPoints(item.symbol); + double requiredStrength = minAllowedStrength * points; + double itemStrength = item.upper - item.lower; + + // + result = + itemStrength > 0 && + requiredStrength > 0 && + itemStrength > requiredStrength; + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Sort | +//+------------------------------------------------------------------+ + +/** + * Allowed Sort Param ... + **/ +enum ENUM_X_SORT_BY +{ + X_SORT_BY_NONE = 0, // None + X_SORT_BY_DATE = 1, // by Date + X_SORT_BY_VALUE = 2, // by Date +}; + +/** + * Check Specified Sort By Validation ... + * + * @param value: ENUM_X_SORT_BY, value to Validate ... + * + * @return ( bool ) + */ +bool IsXValid(ENUM_X_SORT_BY value) +{ + return value != X_SORT_BY_NONE; +} + +/** + * Select Specified Index of a Collection by Sort Params ... + * + * @param source: Collection for Search ... + * @param sortBy: ENUM_X_SORT_BY, Specified Sort Param ... + * @param sortDir: ENUM_X_DIRECTION, Specified Sort Direction ... + * + * @return ( int ) + */ +template +int SelectItemForSorting( + T &source[], + ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE, + ENUM_X_DIRECTION sortDir = X_DIRECTION_BULLISH // +) +{ + // + int result = -1; + + // + // Validate ... + if (!HasChild(source) || + !IsXValid(sortBy) || + !HasDirection(sortDir)) + { + return result; + } + + // + // Sort By Date ... + if (sortBy == X_SORT_BY_DATE) + { + // + // Select Based on Sorting Direction ... + + // + // form Oldest to Youngest ... + if (sortDir == X_DIRECTION_BULLISH) + { + result = GetOldest(source); + } + // + // form Youngest to Oldest ... + else if (sortDir == X_DIRECTION_BEARISH) + { + result = GetYoungest(source); + } + // + // Not Valid ... + else + { + result = -1; + } + } + // + // Sort By Value ... + else if (sortBy == X_SORT_BY_VALUE) + { + // + // form Lowst to Highest ... + if (sortDir == X_DIRECTION_BULLISH) + { + result = GetLowest(source); + } + // + // form Highest to Lowest ... + else if (sortDir == X_DIRECTION_BEARISH) + { + result = GetHighest(source); + } + // + // Not Valid ... + else + { + result = -1; + } + } + // + // Not Valid ... + else + { + result = -1; + } + + // + return result; +} + +/** + * Select Specified Index of a Collection by Sort Params ... + * + * @param source: Collection for Search ... + * @param sortBy: ENUM_X_SORT_BY, Specified Sort Param ... + * @param sortDir: ENUM_X_DIRECTION, Specified Sort Direction ... + * + * @return ( int ) + */ +int SelectBarForSorting( + XOHCL &source[], + ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE, + ENUM_X_DIRECTION sortDir = X_DIRECTION_BULLISH, + ENUM_X_PRICE priceType = X_PRICE_NONE // +) +{ + // + int result = -1; + + // + // Validate ... + if (!HasChild(source) || + !IsXValid(sortBy) || + !HasDirection(sortDir)) + { + return result; + } + + // + // Sort By Date ... + if (sortBy == X_SORT_BY_DATE) + { + // + // Select Based on Sorting Direction ... + + // + // form Oldest to Youngest ... + if (sortDir == X_DIRECTION_BULLISH) + { + result = GetOldest(source); + } + // + // form Youngest to Oldest ... + else if (sortDir == X_DIRECTION_BEARISH) + { + result = GetYoungest(source); + } + // + // Not Valid ... + else + { + result = -1; + } + } + // + // Sort By Value ... + else if (sortBy == X_SORT_BY_VALUE) + { + // + // form Lowst to Highest ... + if (sortDir == X_DIRECTION_BULLISH) + { + result = GetLowest(source, priceType); + } + // + // form Highest to Lowest ... + else if (sortDir == X_DIRECTION_BEARISH) + { + result = GetHighest(source, priceType); + } + // + // Not Valid ... + else + { + result = -1; + } + } + // + // Not Valid ... + else + { + result = -1; + } + + // + return result; +} + +/** + * Apply Sort on Specified Collection ... + * + * @param source: Collection Reference to Sort ... + * @param sortBy: ENUM_X_SORT_BY, Specified Sort Param ... + * @param sortDir: ENUM_X_DIRECTION, Specified Sort Direction ... + * @param maxAllowed: int, Max Allowed Collection Size ... + */ +template +void Sort( + T &source[], + ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE, + ENUM_X_DIRECTION sortDir = X_DIRECTION_BEARISH, + int maxAllowed = 0 // +) +{ + // + int idx = -1; + bool has = false; + + // + // Validate ... + has = + IsXValid(sortBy) && + HasChild(source) && + HasDirection(sortDir); + if (!has) + { + return; + } + + // + // Copy source for Manipulating ... + T tmps[]; + Copy( + source, + tmps // + ); + + // + // Clean Source Collection for Adding Sorted Items ... + Clean(source); + + // + // Loop Through Temp Collection Has Child ... + while (HasChild(tmps)) + { + // + // Select Based on Sorting Parameter ... + idx = SelectItemForSorting( + tmps, + sortBy, + sortDir // + ); + + // + // Validate Detected Index ... + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + // Add Detected Indexed Item to Source ... + AddRef( + tmps[idx], + source // + ); + + // + // Remove Item From Temp Collection ... + ArrayRemove( + tmps, + idx, + 1 // + ); + } + + // + // Cleanup Collection if Max Items Reached ... + if (maxAllowed > 0) + { + // + CleanupArray( + source, + maxAllowed // + ); + } + + // + // Cleanup Resources ... + SpecifiedClean(tmps); +} + +/** + * Apply Sort on Specified Collection ... + * + * @param source: Collection Reference to Sort ... + * @param sortBy: ENUM_X_SORT_BY, Specified Sort Param ... + * @param sortDir: ENUM_X_DIRECTION, Specified Sort Direction ... + * @param priceType: ENUM_X_PRICE, Price Selecting Method ... + * @param maxAllowed: int, Max Allowed Collection Size ... + */ +void SortBar( + XOHCL &source[], + ENUM_X_SORT_BY sortBy = X_SORT_BY_DATE, + ENUM_X_DIRECTION sortDir = X_DIRECTION_BULLISH, + ENUM_X_PRICE priceType = X_PRICE_NONE, + int maxAllowed = 0 // +) +{ + // + int idx = -1; + bool has = false; + + // + // Validate ... + has = + IsXValid(sortBy) && + HasChild(source) && + HasDirection(sortDir); + if (!has) + { + return; + } + + // + // Copy source for Manipulating ... + XOHCL tmps[]; + Copy( + source, + tmps // + ); + + // + // Clean Source Collection for Adding Sorted Items ... + Clean(source); + + // + // Loop Through Temp Collection Has Child ... + while (HasChild(tmps)) + { + // + // Select Based on Sorting Parameter ... + idx = SelectBarForSorting( + tmps, + sortBy, + sortDir, + priceType // + ); + + // + // Validate Detected Index ... + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + // Add Detected Indexed Item to Source ... + AddRef( + tmps[idx], + source // + ); + + // + // Remove Item From Temp Collection ... + ArrayRemove( + tmps, + idx, + 1 // + ); + } + + // + // Cleanup Collection if Max Items Reached ... + if (maxAllowed > 0) + { + // + CleanupArray( + source, + maxAllowed // + ); + } + + // + // Cleanup Resources ... + SpecifiedClean(tmps); +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Extraction | +//+------------------------------------------------------------------+ + +/** + * Extract Specific Types of Pivots From a Collection ... + * + * @param dest: reference Collection to Hold result ... + * @param source: Collection to Find Type Specific items ... + * @param _type: Specified item Type ... + * + * @return ( int ) + */ +int ExtractPivots( + XPivot &dest[], + XPivot &source[], + ENUM_X_PIVOT_TYPE _type // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Validate ... + int count = ArraySize(source); + bool has = + IsXValid(_type) && + IsValidSize(count); + if (!has) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + // Check Type Passing ... + has = _type == source[i].type; + if (!has) + { + continue; + } + + // + AddIfNotExists( + source[i], + dest // + ); + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Extract Same Time Pivots ... + * + * @param item: XPivot, reference to Specified Pivot for Detect Same Times ... + * @param dest: XPivot, collection reference to holds Same Times Pivots ... + * @param source: XPivot, collection reference to Provide Data Source ... + * + * @return ( int ) + */ +int ExtractSameTimePivots( + XPivot &item, + XPivot &dest[], + XPivot &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Validate ... + bool has = HasChild(source) && + item.IsValid(); + if (!has) + { + return result; + } + + // + // Do ... + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = item.time == source[i].time; + if (has) + { + AddIfNotExists(source[i], dest); + } + } + + // + // Add item as a Child ... + AddIfNotExists(item, dest); + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Extract Pivots Data for Linear Regression Calculations ... + * + * @param xData: refrence Collection to Holds X-Axis Data ... + * @param yData: refrence Collection to Holds Y-Axis Data ... + * @param source: pivots Collection for Extraction ... + * + * @return ( int ) + */ +int ExtractPivotsData( + double &xData[], + double &yData[], + XPivot &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(xData); + SpecifiedClean(yData); + + // + // Validate ... + int count = ArraySize(source); + if (!IsValidSize(count)) + { + return result; + } + + // + XOHCL iBar; + bool has = false; + double iX = EMPTY_VALUE; + double iY = EMPTY_VALUE; + for (int i = 0; i < count; i++) + { + // + // Get Pivot Bar ... + has = source[i].GetBar(iBar); + if (!has) + { + continue; + } + + // + iX = iBar.Index(); + iY = source[i].value; + + // + Add( + iX, + xData // + ); + + // + Add( + iY, + yData // + ); + + // + iBar.Clean(); + } + + // + iBar.Clean(); + + // + result = MathMin(ArraySize(xData), ArraySize(yData)); + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Support and Resistance | +//+------------------------------------------------------------------+ +/** + * Extract Support Levels of Pivots Collection ... + * + * @param _minor: refrence to Holds Minor Level ... + * @param _major: refrence to Holds Major Level ... + * @param source: Collection of Pivots ... + * + * @return ( bool ) + */ +bool ExtractSupport( + double &_minor, + double &_major, + XPivot &source[] // +) +{ + // + bool result = false; + + // + // Prepare ... + _minor = EMPTY_VALUE; + _major = EMPTY_VALUE; + + // + // Validate ... + int count = ArraySize(source); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + bool has = false; + double tmp = EMPTY_VALUE; + double iValue = EMPTY_VALUE; + for (int i = 0; i < count; i++) + { + // + // Check Type ... + has = source[i].IsVale(); + if (!has) + { + continue; + } + + // + // Reading Value ... + iValue = source[i].value; + + // + // Check Can Change Major ... + has = !NotEmpty(_major) || + _major > iValue; + if (has) + { + // + tmp = _major; + _major = iValue; + } + // + // Check Can Change Minor ... + else + { + // + // Change Minor ... + has = !NotEmpty(tmp) || + tmp > iValue; + if (has) + { + tmp = iValue; + } + } + } + + // + // Last Update of Minore Minor ... + has = NotEmpty(tmp); + if (has) + { + _minor = tmp; + } + + // + result = NotEmpty(_major) || + NotEmpty(_minor); + + // + return result; +} + +/** + * Extract Resistance Levels of Pivots Collection ... + * + * @param _minor: refrence to Holds Minor Level ... + * @param _major: refrence to Holds Major Level ... + * @param source: Collection of Pivots ... + * + * @return ( bool ) + */ +bool ExtractResistances( + double &_minor, + double &_major, + XPivot &source[] // +) +{ + // + bool result = false; + + // + // Prepare ... + _minor = EMPTY_VALUE; + _major = EMPTY_VALUE; + + // + // Validate ... + int count = ArraySize(source); + result = IsValidSize(count); + if (!result) + { + return result; + } + + // + bool has = false; + double tmp = EMPTY_VALUE; + double iValue = EMPTY_VALUE; + for (int i = 0; i < count; i++) + { + // + // Check Type ... + has = source[i].IsPeak(); + if (!has) + { + continue; + } + + // + // Reading Value ... + iValue = source[i].value; + + // + // Check Can Change Major ... + has = !NotEmpty(_major) || + _major < iValue; + if (has) + { + // + tmp = _major; + _major = iValue; + } + // + // Check Can Change Minor ... + else + { + // + // Change Minor ... + has = !NotEmpty(tmp) || + tmp < iValue; + if (has) + { + tmp = iValue; + } + } + } + + // + // Last Update of Minore Minor ... + has = NotEmpty(tmp); + if (has) + { + _minor = tmp; + } + + // + result = NotEmpty(_major) || + NotEmpty(_minor); + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Find Index | +//+------------------------------------------------------------------+ +/** + * Find Specified Item index in a Collection ... + * + * @param index: int, reference to Hold Index if Exists ... + * @param item: Specified item to Detect ... + * @param source: Collection to Search for item ... + * + * @return ( bool ) + */ +bool FindIndex( + int &index, + XBoxZone &item, + XBoxZone &source[] // +) +{ + // + bool result = false; + + // + index = -1; + + // + int count = ArraySize(source); + result = item.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isSame = item.IsSameAs(source[i]); + if (isSame) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; +} + +/** + * Find Specified Item index in a Collection ... + * + * @param index: int, reference to Hold Index if Exists ... + * @param item: Specified item to Detect ... + * @param source: Collection to Search for item ... + * + * @return ( bool ) + */ +bool FindIndex( + int &index, + XPivot &item, + XPivot &source[] // +) +{ + // + bool result = false; + + // + index = -1; + + // + int count = ArraySize(source); + result = item.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isSame = item.IsSameAs(source[i]); + if (isSame) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; +} + +/** + * Find Specified Item index in a Collection ... + * + * @param index: int, reference to Hold Index if Exists ... + * @param item: Specified item to Detect ... + * @param source: Collection to Search for item ... + * + * @return ( bool ) + */ +bool FindIndex( + int &index, + XDirectionShift &item, + XDirectionShift &source[] // +) +{ + // + bool result = false; + + // + index = -1; + + // + int count = ArraySize(source); + result = item.IsValid() && + IsValidSize(count); + if (!result) + { + return result; + } + + // + for (int i = 0; i < count; i++) + { + // + bool isSame = item.IsSameAs(source[i]); + if (isSame) + { + // + index = i; + break; + } + } + + // + result = IsValidIndex(index); + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Remove | +//+------------------------------------------------------------------+ +/** + * Remove Specified Item from a Collection ... + * + * @param item: Specified Item ... + * @param source: Specified Collection for Remove item from it ... + * + * @return ( bool ) + */ +bool Remove( + XPivot &item, + XPivot &source[] // +) +{ + // + bool result = false; + + // + result = + item.IsValid() && + HasChild(source); + if (!result) + { + return result; + } + + // + int idx = -1; + result = FindIndex( + idx, + item, + source // + ); + if (!result) + { + return result; + } + + // + result = ArrayRemove( + source, + idx, + 1 // + ); + + // + return result; +} + +/** + * Remove Specified Item from a Collection ... + * + * @param item: Specified Item ... + * @param source: Specified Collection for Remove item from it ... + * + * @return ( bool ) + */ +bool Remove( + XBoxZone &item, + XBoxZone &source[] // +) +{ + // + bool result = false; + + // + result = + item.IsValid() && + HasChild(source); + if (!result) + { + return result; + } + + // + int idx = -1; + result = FindIndex( + idx, + item, + source // + ); + if (!result) + { + return result; + } + + // + result = ArrayRemove( + source, + idx, + 1 // + ); + + // + return result; +} + +/** + * Remove Specified Item from a Collection ... + * + * @param item: Specified Item ... + * @param source: Specified Collection for Remove item from it ... + * + * @return ( bool ) + */ +bool Remove( + XDirectionShift &item, + XDirectionShift &source[] // +) +{ + // + bool result = false; + + // + result = + item.IsValid() && + HasChild(source); + if (!result) + { + return result; + } + + // + int idx = -1; + result = FindIndex( + idx, + item, + source // + ); + if (!result) + { + return result; + } + + // + result = ArrayRemove( + source, + idx, + 1 // + ); + + // + return result; +} + +/** + * Remove Specified items from a Collection ... + * + * @param items: Specified Items to Remove ... + * @param sources: Sepcified Collection for Removing items from it ... + * + * @return ( int ) + */ +int Removes( + XBoxZone &items[], + XBoxZone &sources[] // +) +{ + // + int result = 0; + + // + bool has = HasChild(items) && + HasChild(sources); + if (!has) + { + return result; + } + + // + int idx = -1; + has = false; + int count = ArraySize(items); + for (int i = 0; i < count; i++) + { + // + // Detect Item Index in Collection ... + has = FindIndex( + idx, + items[i], + sources // + ); + if (has) + { + // + // Remove Detected Index from Collection ... + has = ArrayRemove( + sources, + idx, + 1 // + ); + + // + if (has) + { + // + // Count Removed Items ... + result++; + } + } + } + + // + return result; +} + +/** + * Remove Specified items from a Collection ... + * + * @param items: Specified Items to Remove ... + * @param sources: Sepcified Collection for Removing items from it ... + * + * @return ( int ) + */ +int Removes( + XPivot &items[], + XPivot &sources[] // +) +{ + // + int result = 0; + + // + bool has = HasChild(items) && + HasChild(sources); + if (!has) + { + return result; + } + + // + int idx = -1; + has = false; + int count = ArraySize(items); + for (int i = 0; i < count; i++) + { + // + // Detect Item Index in Collection ... + has = FindIndex( + idx, + items[i], + sources // + ); + if (has) + { + // + // Remove Detected Index from Collection ... + has = ArrayRemove( + sources, + idx, + 1 // + ); + + // + if (has) + { + // + // Count Removed Items ... + result++; + } + } + } + + // + return result; +} + +/** + * Remove Specified items from a Collection ... + * + * @param items: Specified Items to Remove ... + * @param sources: Sepcified Collection for Removing items from it ... + * + * @return ( int ) + */ +int Removes( + XDirectionShift &items[], + XDirectionShift &sources[] // +) +{ + // + int result = 0; + + // + bool has = HasChild(items) && + HasChild(sources); + if (!has) + { + return result; + } + + // + int idx = -1; + has = false; + int count = ArraySize(items); + for (int i = 0; i < count; i++) + { + // + // Detect Item Index in Collection ... + has = FindIndex( + idx, + items[i], + sources // + ); + if (has) + { + // + // Remove Detected Index from Collection ... + has = ArrayRemove( + sources, + idx, + 1 // + ); + + // + if (has) + { + // + // Count Removed Items ... + result++; + } + } + } + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Add If Not Exists | +//+------------------------------------------------------------------+ +/** + * Add Specified Item to Specified Collection, if not Exists ... + * + * @param item: Item to Add ... + * @param sources: Collection to Add item ... + * @param maxAllowed: int, Max Allowed Collection Size ... + * + * @return ( bool ) + */ +bool AddIfNotExists( + XBoxZone &item, + XBoxZone &sources[], + int maxAllowed = 0 // +) +{ + // + bool result = false; + + // + // Validate Args ... + result = item.IsValid(); + if (!result) + { + return result; + } + + // + // Check Item Exists or not ... + int idx = -1; + bool isExists = FindIndex( + idx, + item, + sources // + ); + result = !isExists; + if (!result) + { + return result; + } + + // + AddRef( + item, + sources // + ); + + // + // Handle Cleanup Collection + // if Max Reached ... + if (result && + maxAllowed > 0) + { + // + CleanupArray( + sources, + maxAllowed // + ); + } + + // + return result; +} + +/** + * Add Specified Item to Specified Collection, if not Exists ... + * + * @param item: Item to Add ... + * @param sources: Collection to Add item ... + * @param maxAllowed: int, Max Allowed Collection Size ... + * + * @return ( bool ) + */ +bool AddIfNotExists( + XPivot &item, + XPivot &sources[], + int maxAllowed = 0 // +) +{ + // + bool result = false; + + // + // Validate Args ... + result = item.IsValid(); + if (!result) + { + return result; + } + + // + // Check Item Exists or not ... + int idx = -1; + bool isExists = FindIndex( + idx, + item, + sources // + ); + result = !isExists; + if (!result) + { + return result; + } + + // + AddRef( + item, + sources // + ); + + // + // Handle Cleanup Collection + // if Max Reached ... + if (result && + maxAllowed > 0) + { + // + CleanupArray( + sources, + maxAllowed // + ); + } + + // + return result; +} + +/** + * Add Specified Item to Specified Collection, if not Exists ... + * + * @param item: Item to Add ... + * @param sources: Collection to Add item ... + * @param maxAllowed: int, Max Allowed Collection Size ... + * + * @return ( bool ) + */ +bool AddIfNotExists( + XDirectionShift &item, + XDirectionShift &sources[], + int maxAllowed = 0 // +) +{ + // + bool result = false; + + // + // Validate Args ... + result = item.IsValid(); + if (!result) + { + return result; + } + + // + // Check Item Exists or not ... + int idx = -1; + bool isExists = FindIndex( + idx, + item, + sources // + ); + result = !isExists; + if (!result) + { + return result; + } + + // + AddRef( + item, + sources // + ); + + // + // Handle Cleanup Collection + // if Max Reached ... + if (result && + maxAllowed > 0) + { + // + CleanupArray( + sources, + maxAllowed // + ); + } + + // + return result; +} + +template +int FillNotExists( + T &dest[], + T &source[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE, + int maxAllowed = 0 // +) +{ + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Normalize ... + maxAllowed = NormalizeInt(maxAllowed, 0); + + // + // Validate ... + bool has = HasChild(source); + if (!has) + { + return result; + } + + // + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = + source[i].IsValid() && + (!HasDirection(forDir) || forDir == source[i].dir); + if (!has) + { + continue; + } + + // + has = AddIfNotExists(source[i], dest); + if (has) + { + result++; + } + } + + // + // Handle Cleanup Collection + // if Max Reached ... + if (maxAllowed > 0) + { + // + CleanupArray( + dest, + maxAllowed // + ); + } + + // + return result; +} +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| Extract | +//+------------------------------------------------------------------+ + +/** + * Extract Specified Directional Items ... + * + * @param dest: reference collection to holds extracted items ... + * @param source: reference collection to provides data source ... + * @param forDir: Specified which direction to Extract items ... + * + * @return ( int ) + */ +template +int ExtractByDirection( + T &dest[], + T &source[], + ENUM_X_DIRECTION forDir // +) +{ + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Validate ... + bool has = HasChild(source) && + HasDirection(forDir); + if (!has) + { + return result; + } + + // + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = source[i].dir == forDir; + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} +//+------------------------------------------------------------------+ + +// +// +// + +//+------------------------------------------------------------------+ +//| Other Extensions | +//+------------------------------------------------------------------+ + +/** + * Validate Boxes ... + * @param box: XBoxZone instance reference for Validate ... + * @param barIndex: int, Bar Index ... + * @param barsLength: int, Bars Length for Validation ... + * + * @return ( bool ) + */ +bool IsBoxValid( + XBoxZone &box, + int barIndex = 0, + int barsLength = 3 // +) +{ + // + bool result = false; + + // + // Normalize Bar Index ... + barIndex = NormalizeInt(barIndex, 0); + barsLength = NormalizeInt(barsLength, 1); + + // + // Ceck Input Box is Valid ... + result = box.IsValid(); + if (!result) + { + return result; + } + + // + // Check Input Box is Breaked or not ... + // Breaktion Found using Counting Over/Under Close Bars ... + bool isBullish = box.IsBullish(); + double appliedPrice = box.GetInDirectionalPrice(); + result = NotEmptyZero(appliedPrice); + if (!result) + { + return result; + } + + // + int toIDX = box.ToIndex(); + + // + XOHCL iBar; + int edgeBreakes = 0; + for (int i = barIndex; i <= toIDX; i++) + { + // + // Initialize Indexed Bar ... + result = iBar.Init( + box.symbol, + box.period, + i // + ); + + // + // Checking Price ... + result = + // + // Checking Bar Validation ... + result && + // + // Checking Price Breaked or not ... + (isBullish + ? iBar.close < box.lower + : iBar.close > box.upper); + if (result) + { + edgeBreakes++; + } + else + { + edgeBreakes = 0; + } + + // + result = edgeBreakes >= barsLength; + if (result) + { + break; + } + + // + iBar.Clean(); + } + + // + iBar.Clean(); + + // + // return true; + + // + result = + edgeBreakes < barsLength; + + // + return result; +} + +// +void SortBoxes( + XBoxZone &items[], + int maxAllowed = 0 // +) +{ + // + int idx = -1; + bool has = false; + + // + has = HasChild(items); + if (!has) + { + return; + } + + // + XBoxZone tmp[]; + Copy( + items, + tmp // + ); + Clean(items); + + // + while (HasChild(tmp)) + { + // + idx = GetOldest(tmp); + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XBoxZone iBox = tmp[idx]; + ArrayRemove( + tmp, + idx, + 1 // + ); + + // + AddRef( + iBox, + items // + ); + } + + // + if (maxAllowed > 0) + { + // + CleanupArray( + items, + maxAllowed // + ); + } + + // + Clean(tmp); +} + +/** + * Check a BaxHas Valid Place for Specified Bar ... + * + * @param bar: XOHCL instance reference, Specified Bar ... + * #param box: XBoxZone instance reference, Specified Box ... + * + * @return ( bool ) + */ +bool IsBoxPlaceValidForBar( + XOHCL &bar, + XBoxZone &box // +) +{ + // + bool result = false; + + // + result = bar.IsValid() && + box.IsValid(); + if (!result) + { + return result; + } + + // + result = + box.IsBullish() + ? bar.low > box.upper + : bar.high < box.upper; + + // + return result; +} + +// +void ValidateBoxes( + XBoxZone &boxes[], + int barIndex = 0, + int barsLength = 3, + bool forceSorting = false, + int maxAllowed = 0 // +) +{ + // + bool has = false; + + // + // Normalize Args ... + barIndex = NormalizeInt(barIndex, 0); + barsLength = NormalizeInt(barsLength, 3); + + // + // Validate Args ... + has = HasChild(boxes); + if (!has) + { + return; + } + + // + // Copy Boxes to tmp ... + XBoxZone tmp[]; + Copy( + boxes, + tmp // + ); + Clean(boxes); + + // + // Looping Through Exists Boxes ... + while (HasChild(tmp)) + { + // + // Select Indexed Box ... + XBoxZone iBox = tmp[0]; + + // + // Remove Indexed Box ... + ArrayRemove( + tmp, + 0, + 1 // + ); + + // + // Check Box Validating ... + has = IsBoxValid( + iBox, + barIndex, + barsLength // + ); + if (has) + { + // + AddRef( + iBox, + boxes // + ); + } + } + + // + // Sorting ... + if (forceSorting) + { + // + // Check Has Result or not ... + has = HasChild(boxes); + if (has) + { + // + // Sorting ... + SortBoxes( + boxes, + maxAllowed // + ); + } + } + + // +} + +void UpdateToTime( + XBoxZone &zones[], + datetime toTime = NULL // +) +{ + // + // Normalize ... + toTime = NormalizeTime(toTime); + + // + // Validate ... + bool has = HasChild(zones); + if (!has) + { + return; + } + + // + int count = ArraySize(zones); + for (int i = 0; i < count; i++) + { + zones[i].to = toTime; + } +} + +/** + * Remove Breaked Zones from a Collection ... + * + * @param source: XBoxZone, reference to Specified Collection ... + * + * @return ( int ) + */ +int RemoveBreakedZones( + XBoxZone &source[], + bool forceBreak = false // +) +{ + // + int result = 0; + + // + // Validate ... + bool has = HasChild(source); + if (!has) + { + return result; + } + + // + XBoxZone iZone; + XBoxZone tmps[]; + Copy( + source, + tmps // + ); + XClean(source); + XOHCL tmpBars[]; + int breakerBars = 0; + while (HasChild(tmps)) + { + // + iZone.Clean(); + iZone = tmps[0]; + ArrayRemove(tmps, 0, 1); + has = IsXValid(iZone.breakAt); + if (has) + { + continue; + } + + // + if (forceBreak) + { + // + breakerBars = GetBreakerBars(iZone, tmpBars); + has = IsValidSize(breakerBars); + } + if (has) + { + continue; + } + + // + AddIfNotExists( + iZone, + source // + ); + } + + // + result = ArraySize(source); + + // + return result; +} + +/** + * Remove Filled Zones ... + * + * @param source: XBoxZone, collection reference to Provide Data Source ... + * @param zoneRangeFilledFactor: double, Filling Factor ... + * + * @return ( int ) + */ +int RemoveFilledZones( + XBoxZone &source[], + double zoneRangeFilledFactor = 0.8 // +) +{ + // + int result = 0; + + // + // Validate ... + bool has = HasChild(source); + if (!has) + { + return result; + } + + // + XBoxZone iTMP; + XBoxZone tmp[]; + Copy(source, tmp); + XClean(source); + while (HasChild(tmp)) + { + // + iTMP.Clean(); + iTMP = tmp[0]; + ArrayRemove(tmp, 0, 1); + + // + has = IsFilled(iTMP, zoneRangeFilledFactor); + if (!has) + { + AddIfNotExists(iTMP, source); + } + } + + // + result = ArraySize(source); + + // + return result; +} + +// #region Zone Converters ... +/** + * Converts a Bar to Pivot ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param pivot: XPivot, reference to holds result ... + * @param forDir: ENUM_X_DIRECTION, specified Pivot Direction ... + * @param prefix: string, Specified Pivot Prefix (used for Object Type) ... + * @param peakPriceType: ENUM_X_PRICE, Specified Peak Pivot's Applied Price ... + * @param valePriceType: ENUM_X_PRICE, Specified Vale Pivot's Applied Price ... + * + * @return ( bool ) + */ +bool ToPivot( + XOHCL &bar, + XPivot &pivot, + ENUM_X_DIRECTION forDir, + string prefix = NULL, + ENUM_X_PRICE peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE valePriceType = X_PRICE_LOW // +) +{ + // + bool result = false; + + // + // Prepare ... + pivot.Clean(); + + // + // Normalize ... + if (!IsXValid(peakPriceType)) + { + peakPriceType = X_PRICE_HIGH; + } + if (!IsXValid(valePriceType)) + { + valePriceType = X_PRICE_LOW; + } + + // + // Validate ... + result = bar.IsValid() && + HasDirection(forDir) && + IsXValid(peakPriceType) && + IsXValid(valePriceType); + if (!result) + { + return result; + } + + // + // Check Direction ... + bool isBullish = IsSpecifiedBullish(forDir); + + // + // Prepare Value of Pivot ... + double iValue = + isBullish + ? bar.GetPrice(valePriceType) + : bar.GetPrice(peakPriceType); + + // + // Prepare Pivot Type ... + ENUM_X_PIVOT_TYPE iType = + isBullish + ? X_PIVOT_TYPE_VALE + : X_PIVOT_TYPE_PEAK; + + // + // Initialize Pivot ... + result = pivot.Init( + iValue, + bar.time, + bar.symbol, + forDir, + bar.period, + iType // + ); + if (result) + { + // + // Set Prefix if Pivot initialized successfully ... + pivot.prefix = prefix; + } + + // + // Validate ... + result = pivot.IsValid(); + if (!result) + { + pivot.Clean(); + } + + // + return result; +} + +/** + * Converts a Bar to Pattern Pivot ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param pivot: XPivot, reference to holds result ... + * @param patternDir: ENUM_X_DIRECTION, specified Pivot Direction ... + * @param pattern: ENUM_X_BAR_PATTERN, Specified Pattern Type ... + * @param peakPriceType: ENUM_X_PRICE, Specified Peak Pivot's Applied Price ... + * @param valePriceType: ENUM_X_PRICE, Specified Vale Pivot's Applied Price ... + * + * @return ( bool ) + */ +bool ToPivot( + XOHCL &bar, + XPivot &pivot, + ENUM_X_DIRECTION patternDir, + ENUM_X_BAR_PATTERN pattern, + ENUM_X_PRICE peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE valePriceType = X_PRICE_LOW // +) +{ + // + bool result = false; + + // + // Prepare ... + pivot.Clean(); + + // + // Normalize ... + if (!IsXValid(peakPriceType)) + { + peakPriceType = X_PRICE_HIGH; + } + if (!IsXValid(valePriceType)) + { + valePriceType = X_PRICE_LOW; + } + + // + // Validate ... + result = bar.IsValid() && + IsXValid(pattern) && + IsXValid(peakPriceType) && + IsXValid(valePriceType) && + HasDirection(patternDir); + if (!result) + { + return result; + } + + // + datetime iTime = bar.time; + string iSymbol = bar.symbol; + string iPrefix = ToXString(pattern); + ENUM_TIMEFRAMES iPeriod = bar.period; + double iValue = IsXBullish(patternDir) + ? bar.GetPrice(X_PRICE_LOW) + : IsXBearish(patternDir) + ? bar.GetPrice(X_PRICE_HIGH) + : EMPTY_VALUE; + ENUM_X_PIVOT_TYPE iType = IsXBullish(patternDir) + ? X_PIVOT_TYPE_VALE + : IsXBearish(patternDir) + ? X_PIVOT_TYPE_PEAK + : X_PIVOT_TYPE_NONE; + + // + result = pivot.Init( + iValue, + iTime, + iSymbol, + patternDir, + iPeriod, + iType // + ); + if (result) + { + pivot.prefix = iPrefix; + } + + // + // Cleanup Resources ... + if (!result) + { + pivot.Clean(); + } + + // + return result; +} + +/** + * Converts POI Bar to Box ... + * + * @param bar: XOHCL, reference to Specified Pattern ... + * @param box: XBoxZone, reference to holds result ... + * @param forDir: ENUM_X_DIRECTION, Specified Pattern Direction ... + * @param prefix: string, Specified Pattern Type ... + * @param peakPriceType: ENUM_X_PRICE, Specified Peak Pivot's Applied Price ... + * @param valePriceType: ENUM_X_PRICE, Specified Vale Pivot's Applied Price ... + * @param setFromByBreakerBar: bool, Set Box From Time to Breaker Bar ... + * + * @return ( bool ) + */ +bool ToBox( + XOHCL &bar, + XBoxZone &box, + ENUM_X_DIRECTION forDir, + string prefix = NULL, + ENUM_X_PRICE peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE valePriceType = X_PRICE_LOW, + bool setFromByBreakerBar = false // +) +{ + // + bool result = false; + + // + // Prepare ... + box.Clean(); + + // + // Normalize ... + if (!IsXValid(peakPriceType)) + { + peakPriceType = X_PRICE_HIGH; + } + if (!IsXValid(valePriceType)) + { + valePriceType = X_PRICE_LOW; + } + + // + // Validate ... + result = bar.IsValid() && + HasDirection(forDir) && + IsXValid(peakPriceType) && + IsXValid(valePriceType); + if (!result) + { + return result; + } + + // + // Check if is Valid Pattern ... + ENUM_X_BAR_PATTERN iPattern = ToBarPattern(prefix); + result = IsXValid(iPattern); + if (result) + { + // + // Conver to Box as Pattern ... + result = ToBox( + bar, + box, + forDir, + iPattern, + peakPriceType, + valePriceType, + setFromByBreakerBar // + ); + } + // + // There is not any Valid Pattern Provided ... + else + { + // + bool isBullish = IsXBullish(forDir); + double peakPrice = bar.GetPrice(peakPriceType); + double valePrice = bar.GetPrice(valePriceType); + + // + string iType = prefix; + datetime iAt = bar.time; + datetime iTo = bar.time; + double iUpper = peakPrice; + double iLower = valePrice; + string iSymbol = bar.symbol; + datetime iFrom = bar.BeforeOn(); + ENUM_TIMEFRAMES iPeriod = bar.period; + + // + // Assign Values to Box ... + box.at = iAt; + box.to = iTo; + box.from = iFrom; + box.type = iType; + box.dir = forDir; + box.upper = iUpper; + box.lower = iLower; + box.symbol = iSymbol; + box.period = iPeriod; + } + + // + // Validate result ... + result = box.IsValid(); + if (!result) + { + // + box.Clean(); + return result; + } + + // + return result; +} + +/** + * Converts Pattern Bar to Box ... + * + * @param bar: XOHCL, reference to Specified Pattern ... + * @param box: XBoxZone, reference to holds result ... + * @param forDir: ENUM_X_DIRECTION, Specified Pattern Direction ... + * @param prefix: string, Specified Pattern Type ... + * @param peakPriceType: ENUM_X_PRICE, Specified Peak Pivot's Applied Price ... + * @param valePriceType: ENUM_X_PRICE, Specified Vale Pivot's Applied Price ... + * @param setFromByBreakerBar: bool, Set Box From Time to Breaker Bar ... + * + * @return ( bool ) + */ +bool ToBox( + XOHCL &bar, + XBoxZone &box, + ENUM_X_DIRECTION patternDir, + ENUM_X_BAR_PATTERN pattern, + ENUM_X_PRICE peakPriceType = X_PRICE_HIGH, + ENUM_X_PRICE valePriceType = X_PRICE_LOW, + bool setFromByBreakerBar = false // +) +{ + // + bool result = false; + + // + // Prepare ... + box.Clean(); + + // + // Normalize ... + if (!IsXValid(peakPriceType)) + { + peakPriceType = X_PRICE_HIGH; + } + if (!IsXValid(valePriceType)) + { + valePriceType = X_PRICE_LOW; + } + + // + // Validate ... + result = bar.IsValid() && + IsXValid(pattern) && + IsXValid(peakPriceType) && + IsXValid(valePriceType) && + HasDirection(patternDir); + if (!result) + { + return result; + } + + // + // Define Requirements ... + XOHCL tmpBar; + XBoxZone tmpBox; + bool has = false; + datetime iAt = bar.time; + datetime iTo = bar.time; + double iUpper = EMPTY_VALUE; + double iLower = EMPTY_VALUE; + string iSymbol = bar.symbol; + datetime iFrom = bar.BeforeOn(); + string iType = ToXString(pattern); + ENUM_TIMEFRAMES iPeriod = bar.period; + + // + bool isBullish = IsXBullish(patternDir); + double peakPrice = bar.GetPrice(peakPriceType); + double valePrice = bar.GetPrice(valePriceType); + + // + // Calculate Requirements Based on Pattern Type and Direction ... + switch (pattern) + { + // + case X_BAR_PATTERN_HIGH: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + has = GetBreakerBar( + bar, + tmpBar, + peakPriceType, + peakPriceType, + X_DIRECTION_BULLISH // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + iUpper = peakPrice; + iLower = bar.GetUp(); + } + break; + + // + case X_BAR_PATTERN_LOW: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + has = GetBreakerBar( + bar, + tmpBar, + valePriceType, + valePriceType, + X_DIRECTION_BEARISH // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + iUpper = bar.GetDown(); + iLower = valePrice; + } + break; + + // + case X_BAR_PATTERN_MOMENTUM: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + iUpper = peakPrice; + iLower = valePrice; + } + break; + + // + case X_BAR_PATTERN_ENGULFED: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + iUpper = peakPrice; + iLower = valePrice; + } + break; + + // + case X_BAR_PATTERN_TRUE_GAPED: { + // + tmpBar.Clean(); + has = bar.GetPreviousBar(tmpBar); + if (has) + { + // + iFrom = tmpBar.time; + + // + iUpper = + isBullish + ? valePrice + : tmpBar.GetPrice(valePriceType); + iLower = + isBullish + ? tmpBar.GetPrice(peakPriceType) + : peakPrice; + } + } + break; + + // + case X_BAR_PATTERN_PINNED: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + iUpper = + isBullish + ? bar.GetDown() + : peakPrice; + iLower = + isBullish + ? valePrice + : bar.GetUp(); + } + break; + + // + case X_BAR_PATTERN_STAR: { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + // + if (setFromByBreakerBar) + { + iFrom = tmpBar.time; + } + + // + int idx = -1; + int mLength = tmpBar.Index() - bar.Index(); + iLower = bar.FindLowest(idx, mLength, valePriceType); + iUpper = bar.FindHighest(idx, mLength, peakPriceType); + } + } + break; + + // + case X_BAR_PATTERN_PIERCING: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + iUpper = peakPrice; + iLower = valePrice; + } + break; + + // + case X_BAR_PATTERN_RISING: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + iUpper = peakPrice; + iLower = valePrice; + } + break; + + // + case X_BAR_PATTERN_FLAG: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + int idx = -1; + int mLength = 3; + iUpper = bar.FindHighest(idx, mLength, peakPriceType); + iLower = bar.FindLowest(idx, mLength, valePriceType); + } + break; + + // + case X_BAR_PATTERN_SIGNALKEY: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + has = bar.GetPreviousBar(tmpBar); + if (has) + { + // + iUpper = MathMax(peakPrice, tmpBar.GetPrice(peakPriceType)); + iLower = MathMin(valePrice, tmpBar.GetPrice(valePriceType)); + } + } + break; + + // + case X_BAR_PATTERN_OB: { + // + tmpBox.Clean(); + has = ToOBBox( + bar, + tmpBox, + patternDir // + ); + if (has) + { + // + iFrom = tmpBox.from; + iUpper = tmpBox.upper; + iLower = tmpBox.lower; + } + } + break; + + // + case X_BAR_PATTERN_FVG: { + // + tmpBox.Clean(); + has = ToFVGBox( + bar, + tmpBox, + patternDir // + ); + if (has) + { + // + iFrom = tmpBox.from; + iUpper = tmpBox.upper; + iLower = tmpBox.lower; + } + } + break; + + // + case X_BAR_PATTERN_SUPPORT: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + iUpper = + isBullish + ? peakPrice + : valePrice; + iLower = + isBullish + ? peakPrice + : valePrice; + } + break; + + // + case X_BAR_PATTERN_RESISTANCE: { + // + if (setFromByBreakerBar) + { + // + tmpBar.Clean(); + ENUM_X_PRICE iPType = isBullish + ? valePriceType + : peakPriceType; + has = GetBreakerBar( + bar, + tmpBar, + iPType, + iPType, + patternDir // + ); + if (has) + { + iFrom = tmpBar.time; + } + } + + // + iUpper = + isBullish + ? peakPrice + : valePrice; + iLower = + isBullish + ? peakPrice + : valePrice; + } + break; + } + + // + // Assign Values to Box ... + box.at = iAt; + box.to = iTo; + box.from = iFrom; + box.type = iType; + box.upper = iUpper; + box.lower = iLower; + box.symbol = iSymbol; + box.period = iPeriod; + box.dir = patternDir; + + // + result = box.IsValid(); + + // + // Cleanup Resources ... + if (!result) + { + box.Clean(); + } + tmpBar.Clean(); + tmpBox.Clean(); + + // + return result; +} + +/** + * Converts Order Flow to Zone ... + * + * @param zone: XBoxZone, reference to holds result ... + * @param orderFlow: XBoxZone, collection reference to provides order flow ... + * + * @return ( bool ) + */ +bool ToBox( + XBoxZone &zone, + XBoxZone &orderFlow[] // +) +{ + // + bool result = false; + + // + // Prepare ... + zone.Clean(); + + // + // Validate ... + result = HasChild(orderFlow); + if (!result) + { + return result; + } + + // + zone = orderFlow[0]; + int idx = GetHighest(orderFlow); + if (IsValidIndex(idx)) + { + zone.upper = orderFlow[idx].upper; + } + idx = GetLowest(orderFlow); + if (IsValidIndex(idx)) + { + zone.lower = orderFlow[idx].lower; + } + + // + zone.type = "XOrderFlowP"; + + // + result = zone.IsValid(); + + // + return result; +} + +/** + * Converts a Bar to OB Box ... + * + * @param bar: XOHCL, Specified Bar ... + * @param box: XBoxZone, destination Box ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( bool ) + */ +bool ToOBBox( + XOHCL &bar, + XBoxZone &box, + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + bool result = false; + + // + // Prepare ... + box.Clean(); + + // + // Normalize ... + if (!HasDirection(forDir)) + { + forDir = bar.GetDirection(); + } + + // + // Validate ... + result = bar.IsValid() && + HasDirection(forDir) && + bar.GetDirection() == forDir; + if (!result) + { + return result; + } + + // + // Detect OB Start Bar ... + XOHCL obStartBar; + result = GetDirectionalBar( + bar, + obStartBar, + Opposit(forDir) // + ); + if (!result) + { + // + obStartBar.Clean(); + return result; + } + + // + box.dir = forDir; + box.to = bar.time; + box.at = bar.time; + box.symbol = bar.symbol; + box.period = bar.period; + box.from = obStartBar.time; + box.type = ToXString(X_BAR_PATTERN_OB); + box.lower = MathMin(obStartBar.low, bar.low); + box.upper = MathMax(obStartBar.high, bar.high); + + // + result = box.IsValid(); + + // + // Cleanup Resources ... + if (!result) + { + box.Clean(); + } + obStartBar.Clean(); + + // + return result; +} + +/** + * Converts a Bar to FVG Box ... + * + * @param bar: XOHCL, Specified Bar ... + * @param box: XBoxZone, destination Box ... + * @param forDir: ENUM_X_DIRECTION, Specified Direction ... + * + * @return ( bool ) + */ +bool ToFVGBox( + XOHCL &bar, + XBoxZone &box, + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + bool result = false; + + // + // Prepare ... + box.Clean(); + + // + // Normalize ... + if (!HasDirection(forDir)) + { + forDir = bar.GetDirection(); + } + + // + // Validate ... + result = bar.IsValid() && + HasDirection(forDir) && + bar.GetDirection() == forDir; + if (!result) + { + return result; + } + + // + // Detect FVG Start Bar ... + XOHCL fvgStartBar; + result = bar.BarAt( + bar.Index() + 2, + fvgStartBar); + if (!result) + { + // + fvgStartBar.Clean(); + return result; + } + + // + bool isBullish = IsXBullish(forDir); + + // + box.dir = forDir; + box.to = bar.time; + box.at = bar.time; + box.upper = + isBullish + ? bar.low + : bar.high; + box.symbol = bar.symbol; + box.period = bar.period; + box.lower = + isBullish + ? fvgStartBar.high + : fvgStartBar.low; + box.from = fvgStartBar.time; + box.type = ToXString(X_BAR_PATTERN_FVG); + + // + result = box.IsValid(); + + // + // Cleanup Resources ... + if (!result) + { + box.Clean(); + } + fvgStartBar.Clean(); + + // + return result; +} + +/** + * Converts a Bar to Support Box ... + * + * @param bar: XOHCL, Specified Bar ... + * @param box: XBoxZone, destination Box ... + * @param toTime: datetime, Specified Box to Time ... + * + * @return ( bool ) + */ +bool ToSupportBox( + XOHCL &bar, + XBoxZone &box, + datetime toTime = NULL, + int validationLength = 0 // +) +{ + // + bool result = false; + + // + // Prepare ... + box.Clean(); + + // + // Normalize ... + toTime = NormalizeTime(toTime); + validationLength = NormalizeInt(validationLength, 0); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL breaker; + result = GetBreakerBar( + bar, + breaker, + X_PRICE_LOW, + X_PRICE_DOWN, + X_DIRECTION_BEARISH, + 500 // + ); + if (!result) + { + breaker.Clean(); + } + + // + box.to = toTime; + box.at = bar.time; + box.from = + breaker.IsValid() + ? breaker.time + : validationLength <= 0 + ? bar.time + : GetBarTime( + bar.symbol, + bar.period, + bar.Index() + validationLength // + ); + box.lower = bar.low; + box.symbol = bar.symbol; + box.period = bar.period; + box.upper = bar.GetDown(); + box.dir = X_DIRECTION_BULLISH; + box.type = ToXString(X_BAR_PATTERN_SUPPORT); + + // + result = box.IsValid(); + if (!result) + { + box.Clean(); + } + + // + return result; +} + +/** + * Converts a Bar to Resistance Box ... + * + * @param bar: XOHCL, Specified Bar ... + * @param box: XBoxZone, destination Box ... + * @param toTime: datetime, Specified Box to Time ... + * + * @return ( bool ) + */ +bool ToResistanceBox( + XOHCL &bar, + XBoxZone &box, + datetime toTime = NULL, + int validationLength = 0 // +) +{ + // + bool result = false; + + // + // Prepare ... + box.Clean(); + + // + // Normalize ... + toTime = NormalizeTime(toTime); + validationLength = NormalizeInt(validationLength, 0); + + // + // Validate ... + result = bar.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL breaker; + result = GetBreakerBar( + bar, + breaker, + X_PRICE_HIGH, + X_PRICE_UP, + X_DIRECTION_BULLISH, + 500 // + ); + if (!result) + { + breaker.Clean(); + } + + // + box.to = toTime; + box.at = bar.time; + box.from = + breaker.IsValid() + ? breaker.time + : validationLength <= 0 + ? bar.time + : GetBarTime( + bar.symbol, + bar.period, + bar.Index() + validationLength // + ); + box.upper = bar.high; + box.symbol = bar.symbol; + box.period = bar.period; + box.lower = bar.GetUp(); + box.dir = X_DIRECTION_BEARISH; + box.type = ToXString(X_BAR_PATTERN_RESISTANCE); + + // + result = box.IsValid(); + if (!result) + { + box.Clean(); + } + + // + return result; +} +// #endregion + +// #region Zone Checkers ... +/** + * Check a Zone is Filled or Not ... + * + * @param zone: XBoxZone, reference to Specified Zone ... + * @param zoneRangeFilledFactor: double, Filling Factor ... + * + * @return ( bool ) + */ +bool IsFilled( + XBoxZone &zone, + double zoneRangeFilledFactor = 0.8 // +) +{ + // + bool result = false; + + // + // Validate ... + result = zone.IsValid() && + zoneRangeFilledFactor > 0 && + zoneRangeFilledFactor < 1; + if (!result) + { + // + result = true; + return result; + } + + // + XOHCL iBar; + int toIDX = zone.ToIndex(); + int fromIDX = zone.FromIndex(); + double zoneRangeFactor = zone.GetRange() / 100; + double useValue = zone.lower + (zoneRangeFactor * zoneRangeFilledFactor); + for (int i = toIDX; i < fromIDX; i++) + { + // + // Initialize Indexed Bar ... + iBar.Clean(); + result = iBar.Init(zone.symbol, zone.period, i); + result = + result && + (zone.IsBullish() + ? iBar.GetPrice(X_PRICE_LOW) <= useValue + : iBar.GetPrice(X_PRICE_HIGH) >= useValue); + if (result) + { + break; + } + } + + // + // Cleanup ... + iBar.Clean(); + + // + return result; +} + +/** + * Check Specified Zone is Breaked by Specified Bar or not ... + * + * @param bar: Specified Bar ... + * @param zone: Specified Zone ... + * @param forceBarEdge: bool, flag to Check Breaktion by high ot low ... + * + * @return ( bool ) + */ +bool IsBreaked( + XOHCL &bar, + XBoxZone &zone, + bool forceBarEdge = false // +) +{ + // + bool result = false; + + // + // Validate ... + result = bar.IsValid() && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Check Break ... + result = + zone.IsBullish() + ? bar.close < zone.lower + : bar.close > zone.upper; + + // + // Apply Force Bar Edge ... + if (forceBarEdge) + { + // + result = + result && + zone.IsBullish() + ? bar.low > zone.upper + : bar.high < zone.lower; + } + + // + return result; +} + +/** + * Check Specified Zone is Tested by Specified Bar or not ... + * + * @param bar: Specified Bar ... + * @param zone: Specified Zone ... + * + * @return ( bool ) + */ +bool IsTested( + XOHCL &bar, + XBoxZone &zone // +) +{ + // + bool result = false; + + // + // Validate ... + result = bar.IsValid() && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Check Test ... + result = + zone.IsBullish() + ? bar.low < zone.upper && bar.low > zone.lower + : bar.high > zone.lower && + bar.high < zone.upper; + + // + return result; +} + +/** + * Check Specified Zone is Rejected by Specified Bar or not ... + * + * @param bar: Specified Bar ... + * @param zone: Specified Zone ... + * + * @return ( bool ) + */ +bool IsRejected( + XOHCL &bar, + XBoxZone &zone // +) +{ + // + bool result = false; + + // + // Validate ... + result = bar.IsValid() && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Check Test ... + result = + IsTested(bar, zone) && + (zone.IsBullish() + ? bar.GetDown() >= zone.upper + : bar.GetUp() <= zone.lower); + + // + return result; +} + +/** + * Check Specified Bar is Inside Specified Zone or not ... + * + * @param bar: Specified Bar ... + * @param zone: Specified Zone ... + * + * @return ( bool ) + */ +bool IsInside( + XOHCL &bar, + XBoxZone &zone // +) +{ + // + bool result = false; + + // + // Validate ... + result = bar.IsValid() && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Check Inside ... + result = + zone.IsBullish() + ? bar.low < zone.upper && + bar.low > zone.lower + : bar.high > zone.lower && + bar.high < zone.upper; + + // + return result; +} + +/** + * Check Specified Bar is Acted On Specified Zone or not ... + * + * @param bar: Specified Bar ... + * @param zone: Specified Zone ... + * + * @return ( bool ) + */ +bool IsActed( + XOHCL &bar, + XBoxZone &zone // +) +{ + // + bool result = false; + + // + // Validate ... + result = bar.IsValid() && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Get Previous Bar ... + XOHCL pBar; + result = bar.GetPreviousBar(pBar); + if (!result) + { + return result; + } + + // + // Previous Bar must one of Following States: + // - Tested; + // - Inside; + // - Breaked; + bool isTested = IsTested(pBar, zone); + bool isInside = IsInside(pBar, zone); + bool isBreaked = IsBreaked(pBar, zone); + result = isTested || + isInside || + isBreaked; + if (!result) + { + return result; + } + + // + // Current Bar Must Close Over / Under Zone ... + result = + zone.IsBullish() + ? bar.close > zone.upper + : zone.IsBearish() + ? bar.close < zone.lower + : false; + + // + // Cleanup Resources ... + pBar.Clean(); + + // + return result; +} + +/** + * Check Specified Zone is Breaked or not ... + * + * @param zone: XBoxZone, reference to Specified Zone ... + * @param priceType: ENUM_X_PRICE, Specified Price Type for Zone Break Detection ... + * + * @return ( bool ) + */ +bool IsBreaked( + XBoxZone &zone, + ENUM_X_PRICE priceType = X_PRICE_CLOSE // +) +{ + // + bool result = false; + + // + // Validate ... + result = zone.IsValid() && + IsXValid(priceType); + if (!result) + { + // + result = true; + return result; + } + + // + XOHCL iBar; + double iPrice; + bool isBullish; + int start = zone.ToIndex(); + int end = zone.FromIndex(); + for (int i = start; i < end; i++) + { + // + // Initialize Indexed Bar ... + iBar.Clean(); + result = iBar.Init(zone.symbol, zone.period, i); + if (!result) + { + // + result = true; + break; + } + + // + isBullish = zone.IsBullish(); + iPrice = iBar.GetPrice(priceType); + result = isBullish + ? iPrice < zone.lower + : iPrice > zone.upper; + if (result) + { + break; + } + } + + // + // Cleanup ... + iBar.Clean(); + + // + return result; +} + +/** + * Check Specified Bar is Acted On Specified Zone or not ... + * + * @param bar: Specified Bar ... + * @param zone: Specified Zone ... + * @param validationLength: Specified Length for Breaks ... + * + * @return ( bool ) + */ +bool IsValidBreaked( + XOHCL &bar, + XBoxZone &zone, + int validationLength = 3 // +) +{ + // + bool result = false; + + // + // Normalize ... + validationLength = NormalizeInt(validationLength, 1); + + // + // Validate ... + result = bar.IsValid() && + zone.IsValid(); + if (!result) + { + return result; + } + + // + XOHCL iBar; + int count = 0; + int start = bar.Index(); + int end = start + validationLength; + for (int i = start; i < end; i++) + { + // + // Initialize Indexed Bar ... + result = bar.BarAt(i, iBar); + if (!result) + { + break; + } + + // + result = IsBreaked(iBar, zone); + if (result) + { + count++; + } + } + + // + result = IsValidSize(count) && + count >= validationLength; + + // + // Cleanup Resources ... + iBar.Clean(); + + // + return result; +} + +/** + * Check Specified Bar is Fake Breaked Specified Zone or not ... + * + * @param bar: Specified Bar ... + * @param zone: Specified Zone ... + * @param validationLength: Specified Length for Breaks ... + * + * @return ( bool ) + */ +bool IsFakeBreaked( + XOHCL &bar, + XBoxZone &zone, + int validationLength = 3 // +) +{ + // + bool result = false; + + // + // Normalize ... + validationLength = NormalizeInt(validationLength, 1); + + // + // Validate ... + result = bar.IsValid() && + zone.IsValid(); + if (!result) + { + return result; + } + + // + // Check Bar Must Acting Zone ... + result = zone.IsBullish() + ? bar.close > zone.upper + : zone.IsBearish() + ? bar.close < zone.lower + : false; + if (!result) + { + return result; + } + + // + // Detect Breaker Bars ... + XOHCL breakerBars[]; + int breakerBarsCount = GetBreakerBars( + zone, + breakerBars // + ); + result = IsValidSize(breakerBarsCount); + if (!result) + { + // + XClean(breakerBars); + return result; + } + + // + // Get Youngest Breaker Bars ... + int idx = GetYoungest(breakerBars); + result = IsValidIndex(idx); + if (!result) + { + // + XClean(breakerBars); + return result; + } + + // + result = breakerBars[idx].Index() - bar.Index() <= validationLength; + + // + // Cleanup Resources ... + XClean(breakerBars); + + // + return result; +} + +/** + * Check Specified ZOne is Affected by Specified Bar or not ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param zone: XBoxZone, reference to Specified Zone ... + * + * @return ( bool ) + */ +bool IsZoneAffected( + XOHCL &bar, + XBoxZone &zone // +) +{ + // + bool result = false; + + // + // Validate ... + result = bar.IsValid() && + zone.IsValid(); + if (!result) + { + return result; + } + + // + bool isActed = IsActed(bar, zone); + bool isTested = IsTested(bar, zone); + bool isFakeBreaked = IsFakeBreaked(bar, zone); + + // + result = isActed || + isTested || + isFakeBreaked; + + // + return result; +} +// #endregion + +// #region Zones Hasers ... +/** + * Check a Bar is Inside a Zone or not ... + * + * @param index: int, reference to holds detected index ... + * @param bar: reference to Specified Bar ... + * @param source: reference collection to provide source ... + * + * @return ( bool ) + */ +bool HasInside( + int &index, + XOHCL &bar, + XBoxZone &source[] // +) +{ + // + XBoxZone selected[]; + int count = ExtractInsides(bar, selected, source); + bool result = IsValidSize(count); + if (result) + { + // + index = GetYoungest(selected); + if (IsValidIndex(index)) + { + result = FindIndex(index, selected[index], source); + } + } + + // + XClean(selected); + + // + return result; +} + +/** + * Check a Bar is Reject a Zone or not ... + * + * @param index: int, reference to holds detected index ... + * @param bar: reference to Specified Bar ... + * @param source: reference collection to provide source ... + * + * @return ( bool ) + */ +bool HasRejected( + int &index, + XOHCL &bar, + XBoxZone &source[] // +) +{ + // + XBoxZone selected[]; + int count = ExtractRejecteds(bar, selected, source); + bool result = IsValidSize(count); + if (result) + { + // + index = GetYoungest(selected); + if (IsValidIndex(index)) + { + result = FindIndex(index, selected[index], source); + } + } + + // + XClean(selected); + + // + return result; +} + +/** + * Check a Bar is Break a Zone or not ... + * + * @param index: int, reference to holds detected index ... + * @param bar: reference to Specified Bar ... + * @param source: reference collection to provide source ... + * + * @return ( bool ) + */ +bool HasBreaked( + int &index, + XOHCL &bar, + XBoxZone &source[] // +) +{ + // + XBoxZone selected[]; + int count = ExtractBreakeds(bar, selected, source); + bool result = IsValidSize(count); + if (result) + { + // + index = GetYoungest(selected); + if (IsValidIndex(index)) + { + result = FindIndex(index, selected[index], source); + } + } + + // + XClean(selected); + + // + return result; +} + +/** + * Check a Bar is Act a Zone or not ... + * + * @param index: int, reference to holds detected index ... + * @param bar: reference to Specified Bar ... + * @param source: reference collection to provide source ... + * + * @return ( bool ) + */ +bool HasActed( + int &index, + XOHCL &bar, + XBoxZone &source[] // +) +{ + // + XBoxZone selected[]; + int count = ExtractActeds(bar, selected, source); + bool result = IsValidSize(count); + if (result) + { + // + index = GetYoungest(selected); + if (IsValidIndex(index)) + { + result = FindIndex(index, selected[index], source); + } + } + + // + XClean(selected); + + // + return result; +} +// #endregion + +// #region Zone Extractors ... +/** + * Extract Affected Zones for Specified Bar ... + * + * @param bar: XOHCL, reference to Specified Bar ... + * @param source: XBoxZone, reference collection to Provide Data Source ... + * @param dest: XBoxZone, reference collection to holds result ... + * @param forDir: ENUM_X_DIRECTION, Specified Zones Direction to Lookup ... + * + * @return ( int ) + */ +int ExtractAffectedZones( + XOHCL &bar, + XBoxZone &source[], + XBoxZone &dest[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Validate ... + bool has = bar.IsValid() && + HasChild(source); + if (!has) + { + return result; + } + + // + bool isActed; + bool isTested; + bool isInside; + bool isFakeBreaked; + for (int i = 0; i < ArraySize(source); i++) + { + // + // Validate Direction ... + has = + !HasDirection(forDir) || + forDir == source[i].dir; + if (!has) + { + continue; + } + + // + // Check Affected ... + isActed = IsActed(bar, source[i]); + isTested = IsTested(bar, source[i]); + isInside = IsInside(bar, source[i]); + isFakeBreaked = IsFakeBreaked(bar, source[i]); + + // + has = + isActed || + isTested || + isInside || + isFakeBreaked; + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Extract all Items which Specified Bar is inside them ... + * + * @param bar: reference to Specified Bar ... + * @param dest: reference to result ... + * @param source: reference collection to provide source ... + * + * @return ( int ) + */ +int ExtractInsides( + XOHCL &bar, + XBoxZone &dest[], + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Validate ... + bool has = bar.IsValid() && + HasChild(source); + if (!has) + { + return result; + } + + // + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = IsInside( + bar, + source[i] // + ); + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Extract all Items which Specified Bar is Acted them ... + * + * @param bar: reference to Specified Bar ... + * @param dest: reference to result ... + * @param source: reference collection to provide source ... + * + * @return ( int ) + */ +int ExtractActeds( + XOHCL &bar, + XBoxZone &dest[], + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Validate ... + bool has = bar.IsValid() && + HasChild(source); + if (!has) + { + return result; + } + + // + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = IsActed( + bar, + source[i] // + ); + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Extract all Items which Specified Bar is Breaked them ... + * + * @param bar: reference to Specified Bar ... + * @param dest: reference to result ... + * @param source: reference collection to provide source ... + * + * @return ( int ) + */ +int ExtractBreakeds( + XOHCL &bar, + XBoxZone &dest[], + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Validate ... + bool has = bar.IsValid() && + HasChild(source); + if (!has) + { + return result; + } + + // + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = IsBreaked( + bar, + source[i] // + ); + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Extract all Items which Specified Bar is Rejected them ... + * + * @param bar: reference to Specified Bar ... + * @param dest: reference to result ... + * @param source: reference collection to provide source ... + * + * @return ( int ) + */ +int ExtractRejecteds( + XOHCL &bar, + XBoxZone &dest[], + XBoxZone &source[] // +) +{ + // + int result = 0; + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Validate ... + bool has = bar.IsValid() && + HasChild(source); + if (!has) + { + return result; + } + + // + int count = ArraySize(source); + for (int i = 0; i < count; i++) + { + // + has = IsRejected( + bar, + source[i] // + ); + if (has) + { + // + AddIfNotExists( + source[i], + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Collect all Bars which Breakes Specified Zone ... + * + * @param zone: reference to Specified Zone ... + * @param dest: reference Collection to hold result ... + * + * @return ( int ) + */ +int GetBreakerBars( + XBoxZone &zone, + XOHCL &dest[] // +) +{ + // + int result = 0; + + // + // Validate ... + bool has = zone.IsValid(); + if (!has) + { + return result; + } + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Do Action ... + XOHCL iBar; + int start = zone.ToIndex(); + int end = zone.FromIndex(); + for (int i = start; i < end; i++) + { + // + // Initialize indexed Bar ... + has = iBar.Init( + zone.symbol, + zone.period, + i // + ); + if (!has) + { + continue; + } + + // + has = IsBreaked( + iBar, + zone, + false // Breakes by Close ... + ); + if (has) + { + // + AddIfNotExists( + iBar, + dest // + ); + } + + // + iBar.Clean(); + } + + // + result = ArraySize(dest); + + // + iBar.Clean(); + + // + return result; +} + +/** + * Collect all Bars which Inside Specified Zone ... + * + * @param zone: reference to Specified Zone ... + * @param dest: reference Collection to hold result ... + * + * @return ( int ) + */ +int GetInsideBars( + XBoxZone &zone, + XOHCL &dest[] // +) +{ + // + int result = 0; + + // + // Validate ... + bool has = zone.IsValid(); + if (!has) + { + return result; + } + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Do Action ... + XOHCL iBar; + int start = zone.ToIndex(); + int end = zone.FromIndex(); + for (int i = start; i < end; i++) + { + // + // Initialize indexed Bar ... + has = iBar.Init( + zone.symbol, + zone.period, + i // + ); + if (!has) + { + continue; + } + + // + has = IsInside( + iBar, + zone // + ); + if (has) + { + // + AddIfNotExists( + iBar, + dest // + ); + } + + // + iBar.Clean(); + } + + // + result = ArraySize(dest); + + // + iBar.Clean(); + + // + return result; +} + +/** + * Collect all Bars which Tested Specified Zone ... + * + * @param zone: reference to Specified Zone ... + * @param dest: reference Collection to hold result ... + * + * @return ( int ) + */ +int GetTesterBars( + XBoxZone &zone, + XOHCL &dest[] // +) +{ + // + int result = 0; + + // + // Validate ... + bool has = zone.IsValid(); + if (!has) + { + return result; + } + + // + // Prepare ... + SpecifiedClean(dest); + + // + // Do Action ... + XOHCL iBar; + int start = zone.ToIndex(); + int end = zone.FromIndex(); + for (int i = start; i < end; i++) + { + // + // Initialize indexed Bar ... + has = iBar.Init( + zone.symbol, + zone.period, + i // + ); + if (!has) + { + continue; + } + + // + has = IsTested( + iBar, + zone // + ); + if (has) + { + // + AddIfNotExists( + iBar, + dest // + ); + } + + // + iBar.Clean(); + } + + // + result = ArraySize(dest); + + // + iBar.Clean(); + + // + return result; +} + +/** + * Validate Zones Range ... + * + * @param source: XBoxZone, collection reference to Validate ... + * @param minAllowedRange: double, min allowed range to Validate ... + * + * @return ( int ) + */ +int ValidateZonesRange( + XBoxZone &source[], + double minAllowedRange // +) +{ + // + int result = 0; + + // + // Validate ... + bool has = HasChild(source) && + minAllowedRange > 0; + if (!has) + { + return result; + } + + // + XBoxZone iTMP; + XBoxZone tmps[]; + Copy(source, tmps); + XClean(source); + while (HasChild(tmps)) + { + // + iTMP.Clean(); + iTMP = tmps[0]; + ArrayRemove(tmps, 0, 1); + + // + // Check Range Validation ... + has = iTMP.GetRange() > minAllowedRange; + if (has) + { + AddIfNotExists(iTMP, source); + } + } + + // + result = ArraySize(source); + + // + // Cleanup ... + XClean(tmps); + iTMP.Clean(); + + // + return result; +} + +/** + * Remove Breaked Zones ... + * + * @param source: XBoxZone, collection reference to Remove Breaked Zones ... + * @param priceType: ENUM_X_PRICE, Specified Price type of Break Detection ... + * + * @return ( int ) + */ +int RemoveBreakedZones( + XBoxZone &source[], + ENUM_X_PRICE priceType = X_PRICE_CLOSE // +) +{ + // + int result = 0; + + // + // Validate ... + if (!HasChild(source) || !IsXValid(priceType)) + { + return result; + } + + // + XBoxZone tmp[]; + Copy(source, tmp); + XClean(source); + XBoxZone iTMP; + bool isBreaked = false; + while (HasChild(tmp)) + { + // + iTMP.Clean(); + iTMP = tmp[0]; + ArrayRemove(tmp, 0, 1); + + // + isBreaked = IsBreaked(iTMP, priceType); + if (!isBreaked) + { + // + AddIfNotExists(iTMP, source); + } + } + + // + result = ArraySize(source); + + // + // Cleanup ... + XClean(tmp); + iTMP.Clean(); + + // + return result; +} +// #endregion +//+------------------------------------------------------------------+ + +// #region Bar Extensions ... +/** + * Check Specified Bar is Breaked or not ... + * + * @param bar: XOHCL, Specified Bar for Checking Proce ... + * @param breakerBar: XOHCL, Hold's Breaker Bar if Exists ... + * @param barIndex: int, Start Checking Bar till Bar's Index ... + * @param breakDir: ENUM_X_DIRECTION, Checking Direction Type, if Bullish Break Price must bigger, otherwise must lower ... + * @param barPriceType: ENUM_X_PRICE, Price type to Check Break ... + * @param breakPriceType: ENUM_X_PRICE, Price Type to Break Bar's Price ... + * + * @return ( bool ) + */ +bool IsBarBreaked( + XOHCL &bar, + XOHCL &breakerBar, + int barIndex = 0, + ENUM_X_DIRECTION breakDir = X_DIRECTION_NONE, + ENUM_X_PRICE barPriceType = X_PRICE_CLOSE, + ENUM_X_PRICE breakPriceType = X_PRICE_CLOSE // +) +{ + // + bool result = false; + + // + // Normalize ... + breakerBar.Clean(); + if (barIndex < 0) + { + barIndex = 0; + } + + // + // Validate ... + result = + bar.IsValid() && + HasDirection(breakDir) && + IsXValid(barPriceType) && + IsXValid(breakPriceType) && + barIndex < bar.Index(); + if (!result) + { + return result; + } + + // + // Loop for Validating ... + XOHCL tmpBar; + bool has = false; + double tmpPrice = EMPTY_VALUE; + double barPrice = bar.GetPrice(barPriceType); + for (int i = barIndex; i < bar.Index(); i++) + { + // + has = tmpBar.Init(bar.symbol, bar.period, i); + if (!has) + { + continue; + } + + // + tmpPrice = tmpBar.GetPrice(breakPriceType); + has = NotEmptyZero(tmpPrice); + if (!has) + { + // + tmpBar.Clean(); + + // + continue; + } + + // + has = + IsXBullish(breakDir) + ? tmpPrice > barPrice + : tmpPrice < barPrice; + if (has) + { + // + breakerBar = tmpBar; + tmpBar.Clean(); + break; + } + + // + tmpBar.Clean(); + } + + // + result = breakerBar.IsValid(); + + // + return result; +} +// #endregion + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.x-poi.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XPOILib +// Description: All models related to POIs ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Classes/x-saherelm.base.class.mq5" +#include "../Libraries/x-saherelm.common.lib.mq5" +#include + +// +// Definitions ... + +/** + * All Available Market Patterns ... + **/ +enum ENUM_X_BAR_PATTERN +{ + X_BAR_PATTERN_NONE = 0, + X_BAR_PATTERN_HIGH = 1, + X_BAR_PATTERN_LOW = 2, + X_BAR_PATTERN_MOMENTUM = 3, + X_BAR_PATTERN_ENGULFED = 4, + X_BAR_PATTERN_TRUE_GAPED = 5, + X_BAR_PATTERN_PINNED = 6, + X_BAR_PATTERN_STAR = 7, + X_BAR_PATTERN_PIERCING = 8, + X_BAR_PATTERN_RISING = 9, + X_BAR_PATTERN_FLAG = 10, + X_BAR_PATTERN_SIGNALKEY = 11, + X_BAR_PATTERN_OB = 12, + X_BAR_PATTERN_FVG = 13, + X_BAR_PATTERN_SUPPORT = 14, + X_BAR_PATTERN_RESISTANCE = 15, + X_BAR_PATTERN_PULLBACK = 16, + X_BAR_PATTERN_CONSOLIDATION = 17, + X_BAR_PATTERN_LEG = 18, +}; + +/** + * Validate an ENUM member ... + * + * @param value: ENUM_X_BAR_PATTERN ... + * + * @return ( bool ) + */ +bool IsXValid(ENUM_X_BAR_PATTERN value) +{ + return value != X_BAR_PATTERN_NONE; +} + +/** + * Converts a Pattern ENUM to String Representation ... + * + * @param value: ENUM_X_BAR_PATTERN, member ... + * + * @return ( string ) + */ +string ToXString(ENUM_X_BAR_PATTERN value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_BAR_PATTERN_NONE: + result = "X_NONE"; + break; + + // + case X_BAR_PATTERN_HIGH: + result = "XHIGHP"; + break; + + // + case X_BAR_PATTERN_LOW: + result = "XLOWP"; + break; + + // + case X_BAR_PATTERN_MOMENTUM: + result = "XMOMENTUMP"; + break; + + // + case X_BAR_PATTERN_ENGULFED: + result = "XENGULFEDP"; + break; + + // + case X_BAR_PATTERN_TRUE_GAPED: + result = "XGAPEDP"; + break; + + // + case X_BAR_PATTERN_PINNED: + result = "XPINNEDP"; + break; + + // + case X_BAR_PATTERN_STAR: + result = "XSTARP"; + break; + + // + case X_BAR_PATTERN_PIERCING: + result = "XPIERCINGP"; + break; + + // + case X_BAR_PATTERN_RISING: + result = "XRISINGP"; + break; + + // + case X_BAR_PATTERN_FLAG: + result = "XFLAGP"; + break; + + // + case X_BAR_PATTERN_SIGNALKEY: + result = "XSIGNALKEYP"; + break; + + // + case X_BAR_PATTERN_OB: + result = "XOBP"; + break; + + // + case X_BAR_PATTERN_FVG: + result = "XFVGP"; + break; + + // + case X_BAR_PATTERN_SUPPORT: + result = "XSUPPORTP"; + break; + + // + case X_BAR_PATTERN_RESISTANCE: + result = "XRESISTANCEP"; + break; + + // + case X_BAR_PATTERN_PULLBACK: + result = "XPULLBACKP"; + break; + + // + case X_BAR_PATTERN_CONSOLIDATION: + result = "XCONSOLIDATIONP"; + break; + + // + case X_BAR_PATTERN_LEG: + result = "XLEGP"; + break; + } + + // + return result; +} + +/** + * Parse an String Representation to it's Corresponding Bar Pattern ENUM ... + * + * @param value: string, provided pattern's string ... + * + * @return ( ENUM_X_BAR_PATTERN ) + */ +ENUM_X_BAR_PATTERN ToBarPattern(string value) +{ + // + ENUM_X_BAR_PATTERN result = X_BAR_PATTERN_NONE; + + // + // Validate ... + if (!IsXValid(value)) + { + return result; + } + + // + if (value == ToXString(X_BAR_PATTERN_NONE)) + { + result = X_BAR_PATTERN_NONE; + } + else if (value == ToXString(X_BAR_PATTERN_HIGH)) + { + result = X_BAR_PATTERN_HIGH; + } + else if (value == ToXString(X_BAR_PATTERN_LOW)) + { + result = X_BAR_PATTERN_LOW; + } + else if (value == ToXString(X_BAR_PATTERN_MOMENTUM)) + { + result = X_BAR_PATTERN_MOMENTUM; + } + else if (value == ToXString(X_BAR_PATTERN_ENGULFED)) + { + result = X_BAR_PATTERN_ENGULFED; + } + else if (value == ToXString(X_BAR_PATTERN_TRUE_GAPED)) + { + result = X_BAR_PATTERN_TRUE_GAPED; + } + else if (value == ToXString(X_BAR_PATTERN_PINNED)) + { + result = X_BAR_PATTERN_PINNED; + } + else if (value == ToXString(X_BAR_PATTERN_STAR)) + { + result = X_BAR_PATTERN_STAR; + } + else if (value == ToXString(X_BAR_PATTERN_PIERCING)) + { + result = X_BAR_PATTERN_PIERCING; + } + else if (value == ToXString(X_BAR_PATTERN_RISING)) + { + result = X_BAR_PATTERN_RISING; + } + else if (value == ToXString(X_BAR_PATTERN_FLAG)) + { + result = X_BAR_PATTERN_FLAG; + } + else if (value == ToXString(X_BAR_PATTERN_SIGNALKEY)) + { + result = X_BAR_PATTERN_SIGNALKEY; + } + else if (value == ToXString(X_BAR_PATTERN_OB)) + { + result = X_BAR_PATTERN_OB; + } + else if (value == ToXString(X_BAR_PATTERN_FVG)) + { + result = X_BAR_PATTERN_FVG; + } + else if (value == ToXString(X_BAR_PATTERN_SUPPORT)) + { + result = X_BAR_PATTERN_SUPPORT; + } + else if (value == ToXString(X_BAR_PATTERN_RESISTANCE)) + { + result = X_BAR_PATTERN_RESISTANCE; + } + else if (value == ToXString(X_BAR_PATTERN_PULLBACK)) + { + result = X_BAR_PATTERN_PULLBACK; + } + else if (value == ToXString(X_BAR_PATTERN_CONSOLIDATION)) + { + result = X_BAR_PATTERN_CONSOLIDATION; + } + else if (value == ToXString(X_BAR_PATTERN_LEG)) + { + result = X_BAR_PATTERN_LEG; + } + + // + return result; +} + +/** + * Get All Available Valid Bar Patterns ... + * + * @param dest: ENUM_X_BAR_PATTERN, reference collection to fill ... + * + * @return ( int ) + */ +int GetAllBarPatters(ENUM_X_BAR_PATTERN &dest[]) +{ + // + XClean(dest); + + // + Add(X_BAR_PATTERN_HIGH, dest); + Add(X_BAR_PATTERN_LOW, dest); + Add(X_BAR_PATTERN_MOMENTUM, dest); + Add(X_BAR_PATTERN_ENGULFED, dest); + Add(X_BAR_PATTERN_TRUE_GAPED, dest); + Add(X_BAR_PATTERN_PINNED, dest); + Add(X_BAR_PATTERN_STAR, dest); + Add(X_BAR_PATTERN_PIERCING, dest); + Add(X_BAR_PATTERN_RISING, dest); + Add(X_BAR_PATTERN_FLAG, dest); + Add(X_BAR_PATTERN_SIGNALKEY, dest); + Add(X_BAR_PATTERN_OB, dest); + Add(X_BAR_PATTERN_FVG, dest); + Add(X_BAR_PATTERN_SUPPORT, dest); + Add(X_BAR_PATTERN_RESISTANCE, dest); + Add(X_BAR_PATTERN_PULLBACK, dest); + Add(X_BAR_PATTERN_CONSOLIDATION, dest); + Add(X_BAR_PATTERN_LEG, dest); + + // + return ArraySize(dest); +} + +/** + * Get All Available Valid Bar Patterns ... + * + * @param dest: ENUM_X_BAR_PATTERN, collection reference to Fill Patterns ... + * @param dir: ENUM_X_DIRECTION, collection reference to Fill Directions ... + * @param forDir: ENUM_X_DIRECTION, Force Patterns Direction ... + * + * @return ( int ) + */ +int GetAllBarPatters( + ENUM_X_BAR_PATTERN &dest[], + ENUM_X_DIRECTION &dir[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + XClean(dest); + XClean(dir); + + // + Add(X_BAR_PATTERN_HIGH, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_LOW, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_MOMENTUM, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_ENGULFED, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_TRUE_GAPED, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_PINNED, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_STAR, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_PIERCING, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_RISING, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_FLAG, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_SIGNALKEY, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_OB, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_FVG, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_SUPPORT, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_RESISTANCE, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_PULLBACK, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_CONSOLIDATION, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_LEG, dest); + Add(forDir, dir); + + // + return ArraySize(dest); +} + +/** + * Fill Required Candlestick Patters ... + * + * @param dest: ENUM_X_BAR_PATTERN, collection reference to Fill ... + * + * @return ( int ) + */ +int GetCandlestickPatterns(ENUM_X_BAR_PATTERN &dest[]) +{ + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + Add(X_BAR_PATTERN_STAR, dest); + Add(X_BAR_PATTERN_FLAG, dest); + Add(X_BAR_PATTERN_PINNED, dest); + Add(X_BAR_PATTERN_RISING, dest); + Add(X_BAR_PATTERN_MOMENTUM, dest); + Add(X_BAR_PATTERN_ENGULFED, dest); + Add(X_BAR_PATTERN_PIERCING, dest); + Add(X_BAR_PATTERN_SIGNALKEY, dest); + Add(X_BAR_PATTERN_TRUE_GAPED, dest); + + // + result = ArraySize(dest); + + // + return result; +} + +/** + * Fill Required Candlestick Patters ... + * + * @param dest: ENUM_X_BAR_PATTERN, collection reference to Fill Patterns ... + * @param dir: ENUM_X_DIRECTION, collection reference to Fill Directions ... + * @param forDir: ENUM_X_DIRECTION, Force Patterns Direction ... + * + * @return ( int ) + */ +int GetCandlestickPatterns( + ENUM_X_BAR_PATTERN &dest[], + ENUM_X_DIRECTION &dir[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE // +) +{ + // + int result = 0; + + // + // Prepare ... + XClean(dest); + XClean(dir); + + // + Add(X_BAR_PATTERN_STAR, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_FLAG, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_PINNED, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_RISING, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_MOMENTUM, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_ENGULFED, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_PIERCING, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_SIGNALKEY, dest); + Add(forDir, dir); + + // + Add(X_BAR_PATTERN_TRUE_GAPED, dest); + Add(forDir, dir); + + // + result = ArraySize(dest); + + // + return result; +} + +// +// Structures ... + +/** + * Model a Trend Line ... + **/ +struct XTrend +{ + // + string symbol; + datetime time; + ENUM_TIMEFRAMES period; + + // + double fromValue; + datetime fromTime; + + // + double toValue; + datetime toTime; + + // + ENUM_X_DIRECTION dir; + + // + // Constructor ... + XTrend() + { + Clean(); + } + + // + // Tools ... + + /** + * Initialize ... + * + * @param _symbol: string, Specified Symbol ... + * @param _period: ENUM_TIMEFRAMES, Specified Period ... + * @param _time: datetime, Detection Time ... + * @param _fromValue: double, From Value ... + * @param _fromTime: datetime, From Time ... + * @param _toValue: double, To Value ... + * @param _toTime: datetime, To Time ... + * + * @return ( bool ) + */ + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period, + datetime _time, + double _fromValue, + datetime _fromTime, + double _toValue, + datetime _toTime // + ) + { + // + bool result = false; + + // + time = _time; + symbol = _symbol; + period = _period; + toTime = _toTime; + toValue = _toValue; + fromTime = _fromTime; + fromValue = _fromValue; + + // + result = IsValid(); + if (!result) + { + Clean(); + } + + // + // Setting Direction ... + if (result) + { + // + dir = + fromValue < toValue + ? X_DIRECTION_BULLISH + : fromValue > toValue + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + return result; + } + + /** + * Cleanup ... + */ + void Clean() + { + // + time = NULL; + toValue = 0; + fromValue = 0; + symbol = NULL; + period = NULL; + toTime = NULL; + fromTime = NULL; + dir = X_DIRECTION_NONE; + + // + ZeroMemory(this); + } + + /** + * Validate ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + IsXValid(time) && + IsXValid(symbol) && + IsXValid(period) && + IsXValid(toTime) && + IsXValid(fromTime) && + NotEmptyZero(toValue) && + NotEmptyZero(fromValue) && + fromTime < toTime; + + // + return result; + } + + /** + * Check Trend Has Specific Direction ... + * + * @return ( bool ) + */ + bool HasTrend() + { + return IsValid() && + HasDirection(dir); + } + + /** + * Check Trend is Bullish ... + * + * @return ( bool ) + */ + bool IsBullish() + { + return HasTrend() && + IsXBullish(dir); + } + + /** + * Check Trend is Bearish ... + * + * @return ( bool ) + */ + bool IsBearish() + { + return HasTrend() && + IsXBearish(dir); + } + + /** + * Get Unique Identifier ... + * + * @return ( string ) + */ + string GetObjectID() + { + // + string result = NULL; + + // + if (IsValid()) + { + double ifv = NormalizePrice(fromValue, symbol); + result = "XTRND_" + ToXString(dir) + "_" + ToXString(ifv) + "_" + ToXString(TimeToSeconds(fromTime)); + } + + // + return result; + } +}; + +/** + * Represent a Pivot ... + **/ +struct XPivot +{ + // + // Props ... + double value; // Value + datetime time; // Time + string symbol; // Symbol + ENUM_X_DIRECTION dir; // Direction + ENUM_TIMEFRAMES period; // Period + ENUM_X_PIVOT_TYPE type; // Type + + // + string prefix; // Object Prefix + + // + // Constructor ... + XPivot() + { + Clean(); + } + + // + // Init ... + + /** + * Initialize Structure ... + * + * @param _value: double, value of point ... + * @param _time: datetime, time of point ... + * @param _symbol: string, Symbol ... + * @param _dir: ENUM_X_DIRECTION, direction of point ... + * @param _period: ENUM_TIMEFRAMES, period ... + * @param _type: ENUM_X_PIVOT_TYPE, point type ... + * + * @return ( bool ) + */ + bool Init( + double _value, + datetime _time, + string _symbol, + ENUM_X_DIRECTION _dir, + ENUM_TIMEFRAMES _period, + ENUM_X_PIVOT_TYPE _type // + ) + { + // + bool result = false; + + // + dir = _dir; + time = _time; + type = _type; + value = _value; + symbol = _symbol; + period = _period; + + // + result = IsValid(); + if (!result) + { + Clean(); + } + + // + return result; + } + + // + // Tools ... + + /** + * Cleanup Model ... + */ + void Clean() + { + // + value = 0; + time = NULL; + symbol = NULL; + period = NULL; + prefix = NULL; + dir = X_DIRECTION_NONE; + type = X_PIVOT_TYPE_NONE; + + // + ZeroMemory(this); + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + value > 0 && + IsXValid(type) && + HasDirection(dir) && + IsSpecifiedValid(time) && + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period); + + // + return result; + } + + /** + * Check Model is Peak or not ... + * + * @return ( bool ) + */ + bool IsPeak() + { + // + bool result = false; + + // + result = + IsValid() && + IsXPeak(type); + + // + return result; + } + + /** + * Check Model is Vale or not ... + * + * @return ( bool ) + */ + bool IsVale() + { + // + bool result = false; + + // + result = + IsValid() && + IsXVale(type); + + // + return result; + } + + /** + * Check Point is Bullish or not ... + * + * @return ( bool ) + */ + bool IsBullish() + { + // + bool result = false; + + // + result = IsValid() && + IsSpecifiedBullish(dir); + + // + return result; + } + + /** + * Check Point is Bearish or not ... + * + * @return ( bool ) + */ + bool IsBearish() + { + // + bool result = false; + + // + result = IsValid() && + IsSpecifiedBearish(dir); + + // + return result; + } + + /** + * Check two Struct are Same or not ... + * + * @param item: XPivot ... + * + * @return ( bool ) + */ + bool IsSameAs(XPivot &item) + { + // + bool result = false; + + // + result = + IsValid() && + item.IsValid() && + dir == item.dir && + type == item.type && + time == item.time && + value == item.value && + symbol == item.symbol && + period == item.period; + + // + if (result && IsXValid(prefix)) + { + // + result = + result && + prefix == item.prefix; + } + + // + return result; + } + + /** + * Calculate Pivot Age ... + * + * @return ( int ) + */ + int GetAge() + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetBarIndex( + symbol, + period, + time // + ); + + // + return result; + } + + /** + * Get Pivot Time Bar ... + * + * @param bar: XOHCL, reference to hold result ... + * + * @return ( bool ) + */ + bool GetBar(XOHCL &bar) + { + // + bool result = false; + + // + // Prepare ... + bar.Clean(); + + // + // Validate ... + result = IsValid(); + if (!result) + { + return result; + } + + // + // Initial Bar ... + result = bar.Init( + symbol, + period, + time // + ); + + // + if (!result) + { + bar.Clean(); + } + + // + return result; + } + + /** + * Check to model Has Same Symbol ... + * + * @param item: XPivot, dest model for Checking ... + * + * @return ( bool ) + */ + bool IsSameSymbolAs(XPivot &item) + { + // + bool result = false; + + // + result = + IsValid() && + item.IsValid() && + symbol == item.symbol; + + // + return result; + } + + /** + * Check to model Has Same Period ... + * + * @param item: XPivot, dest model for Checking ... + * + * @return ( bool ) + */ + bool IsSamePeriodAs(XPivot &item) + { + // + bool result = false; + + // + result = + IsValid() && + item.IsValid() && + period == item.period; + + // + return result; + } + + /** + * Check to model Has Same Symbol/Period ... + * + * @param item: XPivot, dest model for Checking ... + * + * @return ( bool ) + */ + bool IsSameMarketAs(XPivot &item) + { + // + bool result = false; + + // + result = + IsValid() && + item.IsValid() && + IsSameSymbolAs(item) && + IsSamePeriodAs(item); + + // + return result; + } + + /** + * Check to model Has Same Type ... + * + * @param item: XPivot, dest model for Checking ... + * + * @return ( bool ) + */ + bool IsSameTypeAs(XPivot &item) + { + // + bool result = false; + + // + result = + IsValid() && + item.IsValid() && + type == item.type; + + // + return result; + } + + /** + * Check to model Has Same Direction ... + * + * @param item: XPivot, dest model for Checking ... + * + * @return ( bool ) + */ + bool IsSameDirectionAs(XPivot &item) + { + // + bool result = false; + + // + result = + IsValid() && + item.IsValid() && + dir == item.dir; + + // + return result; + } + + // + // Logging Tools ... + + /** + * Extract Specified Token of Struct ... + * + * @return ( string ) + */ + string GetTag() + { + // + string result = NULL; + + // + string token = GetToken(this); + + // + result = + (IsSpecifiedValid(prefix) + ? prefix + "_" + : "") + + token; + + // + return result; + } + + /** + * Represent an String Unique Identifier for Chart Objects ... + * + * @return ( string ) + */ + string GetObjectID() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetTag() + "_" + symbol + "_" + ToXString(period) + "_" + ToXString(dir) + "_" + ToXString(type) + "_" + ToXString(TimeToSeconds(time)); + + // + return result; + } + + /** + * Represent a Point as String ... + * + * @param spacer: string, How to Represent Spaces ... + * + * @return ( string ) + */ + string GetMessage(string spacer = NULL) + { + // + string result = ""; + + // + // Normalize Spacer ... + if (!IsSpecifiedValid(spacer)) + { + spacer = " "; + } + + // + // Validate ... + if (!IsValid()) + { + return result; + } + + // + result = + ToXString(dir) + spacer + GetTag() + ":" + spacer + + "Symbol: " + symbol + spacer + + "Period: " + ToXString(period) + spacer + + "Type: " + ToXString(type) + spacer + + "Direction: " + ToXString(dir) + spacer + + "Value: " + ToXString(value) + spacer + + "Time: " + ToXString(time) + spacer; + + // + return result; + } +}; + +/** + * Model a Box ... + **/ +struct XBoxZone +{ + // + // Props ... + string symbol; + ENUM_TIMEFRAMES period; + + // + double upper; + double lower; + + // + datetime at; + datetime from; + datetime to; + + // + string type; + ENUM_X_DIRECTION dir; + + // + // Special Props ... + datetime breakAt; + datetime tests[]; + datetime acteds[]; + datetime breaks[]; + datetime insides[]; + datetime refines[]; + datetime fakeBreaks[]; + + // + // Constructor ... + XBoxZone() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup Model ... + */ + void Clean() + { + // + upper = 0; + lower = 0; + to = NULL; + at = NULL; + from = NULL; + symbol = NULL; + period = NULL; + dir = X_DIRECTION_NONE; + + // + SpecialClean(); + + // + ZeroMemory(this); + } + + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period, + double _upper, + double _lower, + datetime _from, + datetime _to, + ENUM_X_DIRECTION _dir, + string _type = "", + datetime _at = NULL // + ) + { + // + bool result = false; + + // + // Validate ... + result = IsXValid(_symbol) && + IsXValid(_period) && + _upper > 0 && + _lower > 0 && + _upper > _lower && + IsXValid(_from) && + IsXValid(_to) && + _from < _to && + HasDirection(_dir); + if (!result) + { + return result; + } + + // + this.to = _to; + this.at = _at; + this.dir = _dir; + this.from = _from; + this.type = _type; + this.lower = _lower; + this.upper = _upper; + this.symbol = _symbol; + this.period = _period; + + // + result = IsValid(); + if (!result) + { + Clean(); + } + + // + return result; + } + + /** + * Clean Special Props ... + */ + void SpecialClean() + { + // + breakAt = NULL; + XClean(tests); + XClean(acteds); + XClean(breaks); + XClean(insides); + XClean(refines); + XClean(fakeBreaks); + } + + /** + * Validate Model ... + * + * @return ( bool ) + */ + bool IsValid() + { + // + bool result = false; + + // + result = + // + upper > 0 && + lower > 0 && + from < to && + IsSpecifiedValid(to) && + upper >= lower && + IsSpecifiedValid(from) && + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) + // + ; + + // + return result; + } + + /** + * Check Box is Bullish or not ... + * + * @return ( bool ) + */ + bool IsBullish() + { + return IsValid() && + IsSpecifiedBullish(dir); + } + + /** + * Check Box is Bearish or not ... + * + * @return ( bool ) + */ + bool IsBearish() + { + return IsValid() && + IsSpecifiedBearish(dir); + } + + /** + * Clone Box by Provided Source ... + * + * @return ( bool ) + */ + bool Clone(XBoxZone &source) + { + // + bool result = false; + + // + Clean(); + result = source.IsValid(); + if (!result) + { + return result; + } + + // + // Filling Props ... + to = source.to; + dir = source.dir; + from = source.from; + type = source.type; + upper = source.upper; + lower = source.lower; + symbol = source.symbol; + period = source.period; + + // + result = IsValid(); + if (!result) + { + Clean(); + } + + // + return result; + } + + /** + * Check Box is Same as Other ... + * + * @param item: XBoxZone instance Resource ... + * + * @return ( bool ) + */ + bool IsSameAs(XBoxZone &item) + { + // + return IsValid() && + item.IsValid() && + dir == item.dir && + from == item.from && + type == item.type && + lower == item.lower && + upper == item.upper && + symbol == item.symbol && + period == item.period; + } + + /** + * Retrieve Box Age ... + * + * @param forPeriod: ENUM_TIMEFRAMES member ... + * + * @return ( int ) + */ + int GetAge( + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + int result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = period; + } + + // + result = iBarShift( + symbol, + forPeriod, + from // + ); + + // + return result; + } + + /** + * Calculate Box Middle Price ... + * + * @return ( double ) + */ + double GetMid() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + double diffAvg = (upper - lower) / 2; + result = lower + diffAvg; + result = NormalizePrice(result, symbol); + + // + return result; + } + + /** + * Calculate Box Leg N Price ... + * N default is 2 + * + * @param leg: int ... + * + * @return ( double ) + */ + double GetLeg(int leg = 2) + { + // + double result = 0; + + // + leg = NormalizeInt(leg, 2); + + // + if (!IsValid()) + { + return result; + } + + // + double range = (upper - lower) * leg; + result = + IsBullish() + ? upper + range + : lower - range; + result = NormalizePrice(result, symbol); + + // + return result; + } + + /** + * Calculate Box Range ... + * + * @return ( double ) + */ + double GetRange() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = (upper - lower); + result = NormalizePrice(result, symbol); + + // + return result; + } + + /** + * Retrieve Box Applied Price ... + * + * @return ( double ) + */ + double GetDirectionalPrice() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + IsBullish() + ? upper + : lower; + + // + return result; + } + + /** + * Retrieve Box Breaked Price ... + * + * @return ( double ) + */ + double GetInDirectionalPrice() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = + IsBullish() + ? lower + : upper; + + // + return result; + } + + /** + * To Bar Index ... + * + * @return ( int ) + */ + int ToIndex( + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = period; + } + + // + result = GetBarIndex( + symbol, + forPeriod, + to // + ); + + // + return result; + } + + /** + * Retrieve To Bar ... + * + * @return ( bool ) + */ + bool ToBar(XOHCL &bar) + { + // + bool result = false; + + // + bar.Clean(); + + // + int idx = ToIndex(); + + // + result = + IsValid() && + IsValidIndex(idx); + if (!result) + { + return result; + } + + // + result = bar.Init( + symbol, + period, + idx // + ); + + // + return result; + } + + /** + * At Bar Index ... + * + * @return ( int ) + */ + int AtIndex( + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + int result = -1; + + // + if (!IsValid() || !IsXValid(at)) + { + return result; + } + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = period; + } + + // + result = GetBarIndex( + symbol, + forPeriod, + at // + ); + + // + return result; + } + + /** + * Retrieve At Bar ... + * + * @return ( bool ) + */ + bool AtBar(XOHCL &bar) + { + // + bool result = false; + + // + bar.Clean(); + + // + int idx = AtIndex(); + + // + result = + IsValid() && + IsValidIndex(idx); + if (!result) + { + return result; + } + + // + result = bar.Init( + symbol, + period, + idx // + ); + + // + return result; + } + + /** + * From Bar Index ... + * + * @return ( int ) + */ + int FromIndex( + ENUM_TIMEFRAMES forPeriod = NULL // + ) + { + // + int result = -1; + + // + if (!IsValid()) + { + return result; + } + + // + if (!IsSpecifiedValid(forPeriod)) + { + forPeriod = period; + } + + // + result = GetBarIndex( + symbol, + forPeriod, + from // + ); + + // + return result; + } + + /** + * Retrieve From Bar ... + * + * @return ( bool ) + */ + bool FromBar(XOHCL &bar) + { + // + bool result = false; + + // + bar.Clean(); + + // + int idx = FromIndex(); + + // + result = + IsValid() && + IsValidIndex(idx); + if (!result) + { + return result; + } + + // + result = bar.Init( + symbol, + period, + idx // + ); + + // + return result; + } + + /** + * Retrieve Unique Identifier ... + * + * @return ( string ) + */ + string GetTag() + { + // + int digits = GetDigits(symbol); + double nUpper = NormalizeDouble(NormalizePrice(upper, symbol), digits); + double nLower = NormalizeDouble(NormalizePrice(lower, symbol), digits); + + // + string typeStr = IsSpecifiedValid(type) + ? type + : "XBOX"; + string result = + // + typeStr + "_" + + ToString(dir) + "_" + + symbol + "_" + + ToXString(period) + "_" + + ToXString(nUpper) + "_" + + ToXString(nLower) + // + ; + + // + return result; + } + + /** + * Retrieve Unique Middle Identifier ... + * + * @return ( string ) + */ + string GetMiddleTag() + { + // + int digits = GetDigits(symbol); + double nMid = NormalizeDouble(NormalizePrice(GetMid(), symbol), digits); + + // + string typeStr = IsSpecifiedValid(type) + ? type + : "XBOX"; + string result = + // + typeStr + "_" + + "Mid_" + + ToString(dir) + "_" + + symbol + "_" + + ToXString(period) + "_" + + ToXString(nMid) + // + ; + + // + return result; + } +}; + +/** + * Model a Direction Shift ... + **/ +struct XDirectionShift +{ + // + // Props ... + string type; + datetime at; + double after; + double before; + string symbol; + ENUM_TIMEFRAMES period; + ENUM_X_DIRECTION shiftTo; + + // + // Constructor ... + XDirectionShift() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + at = NULL; + after = 0; + before = 0; + type = NULL; + symbol = NULL; + period = NULL; + shiftTo = X_DIRECTION_NONE; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + after > 0 && + IsSpecifiedValid(at) && + IsSpecifiedValid(type) && + after != before && + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + HasDirection(shiftTo); + + // + return result; + } + + // + bool Init( + string _type, + datetime _at, + double _after, + double _before, + string _symbol, + ENUM_TIMEFRAMES _period, + ENUM_X_DIRECTION _shiftTo // + ) + { + // + bool result = false; + + // + // Validate ... + result = + IsXValid(_at) && + IsXValid(_type) && + IsXValid(_symbol) && + IsXValid(_period) && + NotEmptyZero(_after) && + NotEmptyZero(_before) && + HasDirection(_shiftTo); + if (!result) + { + return result; + } + + // + type = _type; + at = _at; + after = _after; + before = _before; + symbol = _symbol; + period = _period; + shiftTo = _shiftTo; + + // + result = IsValid(); + + // + return result; + } + + // + // Get Bar Index of Direction Shift ... + int Index() + { + // + int result = -1; + + // + // Validate ... + if (!IsValid()) + { + return result; + } + + // + // Retrieve Bar Index ... + result = GetBarIndex( + symbol, + period, + at // + ); + + // + return result; + } + + // + // Get At Bar ... + bool AtBar(XOHCL &bar) + { + // + bool result = false; + + // + // Normalize ... + bar.Clean(); + + // + // Validate ... + result = IsValid(); + if (!result) + { + return result; + } + + // + int idx = Index(); + if (IsValidIndex(idx)) + { + // + result = bar.Init( + symbol, + period, + idx // + ); + } + + // + result = bar.IsValid(); + + // + return result; + } + + // + // Check Same ... + bool IsSameAs(XDirectionShift &item) + { + // + bool result = false; + + // + result = IsValid() && + item.IsValid(); + if (!result) + { + return result; + } + + // + result = + // + at == item.at && + type == item.type && + after == item.after && + before == item.before && + symbol == item.symbol && + period == item.period && + shiftTo == item.shiftTo + // + ; + + // + return result; + } +}; + +/** + * Configure Draws ... + **/ +struct XPOIDrawConfig +{ + // + // Props ... + + // + color bullishColor; + color bearishColor; + color neuturalColor; + + // + int arrowsWidth; + int bullishArrow; + int bearishArrow; + int arrowsThreshold; + ENUM_X_PRICE arrowsValePriceType; + ENUM_X_PRICE arrowsPeakPriceType; + + // + int zonesWidth; + bool zonesFill; + bool ignoreZonesAt; + ENUM_LINE_STYLE zonesStyle; + + // + int trendWidth; + bool trendRayLeft; + bool trendRayRight; + ENUM_LINE_STYLE trendStyle; + + // + // Constructor ... + XPOIDrawConfig() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup ... + */ + void Clean() + { + // + bullishColor = CLR_NONE; + bearishColor = CLR_NONE; + neuturalColor = CLR_NONE; + + // + arrowsWidth = 0; + bullishArrow = 0; + bearishArrow = 0; + arrowsThreshold = 0; + arrowsValePriceType = X_PRICE_NONE; + arrowsPeakPriceType = X_PRICE_NONE; + + // + zonesWidth = 1; + zonesFill = false; + ignoreZonesAt = true; + zonesStyle = STYLE_SOLID; + + // + trendWidth = 0; + trendRayLeft = false; + trendRayRight = false; + trendStyle = STYLE_DOT; + } + + /** + * Default Config ... + */ + void Default() + { + // + bullishColor = clrAqua; + bearishColor = clrMagenta; + neuturalColor = clrGray; + + // + arrowsWidth = 1; + bullishArrow = 159; + bearishArrow = 159; + arrowsThreshold = 5; + arrowsValePriceType = X_PRICE_LOW; + arrowsPeakPriceType = X_PRICE_HIGH; + + // + zonesWidth = 1; + zonesFill = true; + ignoreZonesAt = true; + zonesStyle = STYLE_SOLID; + + // + trendWidth = 2; + trendRayLeft = false; + trendRayRight = true; + trendStyle = STYLE_DOT; + } + + // +}; + +// + +### FILE: C:\Users\SaherElm\AppData\Roaming\MetaQuotes\Terminal\572C4A1F743028C65C8BA0B780030F0D\MQL5\Libraries\x-saherelm.x-trade.lib.mq5 + +/////////////////////////////////////////////////////// +// +// SaherElm IT Center MQL5 Seriallize Library +// --------------------------------------- +// Name: XTradeLib +// Description: All models related to Trade ... +// +// +// Maintainer: +// ------------ +// Hadi Khazaee Asl (hadi_khazaee_asl@yahoo.com) +// +////////////////////////////////////////////////////// +// +// Global Properties ... +#property library +#property copyright "Copyright 2023, SaherElm IT Center" +#property link "https://www.saherelm.ir" +#property version "1.00" +#property strict + +// +// Imports ... +#include "../Libraries/x-saherelm.common.lib.mq5" +#include "../Libraries/x-saherelm.x-guard.lib.mq5" +#include + +// +// Definitions ... + +// +// a List of Used Tokens ... + +// +// Common ... +string XIDToken = "ID"; +string XTicketToken = "TK"; +string XModeToken = "MD"; +string XTypeToken = "TY"; +string XPeriodToken = "PR"; +string XProviderToken = "PRV"; +string XProfitToken = "PF"; + +// +string XTPToken = "TP"; +string XSLToken = "SL"; +string XTimeToken = "TM"; +string XEntryToken = "EN"; +string XVolumeToken = "VL"; +string XSymbolToken = "SMBL"; + +// +string XSupportToken = "SP"; +string XEQMSupportToken = "EQM"; +string XEQPToken = "EQP"; + +// +string XSLTrailToken = "SLT"; + +// +string XActionToken = "A"; + +// +string XDirectionalToken = "D"; +string XINDirectionalToken = "IND"; + +// +string XRecoveryToken = "XRCV"; + +// +// Available Order Modes ... +enum ENUM_X_ORDER_MODES +{ + X_ORDER_MODE_NOTHING, // Nothing + X_ORDER_MODE_MARKET, // Market Order + X_ORDER_MODE_STOP, // Pending Stop Order + X_ORDER_MODE_LIMIT, // Pending Limit Order + X_ORDER_MODE_STOP_LIMIT, // Pending Stop Limit Order +}; + +// +string ToString(ENUM_X_ORDER_MODES value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_ORDER_MODE_MARKET: + result = "Market"; + break; + + // + case X_ORDER_MODE_LIMIT: + result = "Limit"; + break; + + // + case X_ORDER_MODE_STOP: + result = "Stop"; + break; + + // + case X_ORDER_MODE_STOP_LIMIT: + result = "StopLimit"; + break; + } + + // + return result; +} + +// +// Select Positions Type ... +enum ENUM_X_POSITION_SELECT_METHODS +{ + X_POSITION_SELECT_NONE, // None + X_POSITION_SELECT_MAX, // Max + X_POSITION_SELECT_MIN, // Min + X_POSITION_SELECT_BOTH, // Min and Max + X_POSITION_SELECT_ALL, // All +}; + +// +// Signal Execution Result ... +// note that some of them must be handles in +// EA's ... +enum ENUM_X_SIGNAL_EXECUTION_RESULT +{ + // + X_SIGNAL_EXECUTION_UNKNOWN, // Unknown + X_SIGNAL_EXECUTION_SUCCEED, // Succed + X_SIGNAL_EXECUTION_FAILED_SPREAD, // Spread more than Max Allowed + X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED, // Not Allowed Trade Type + X_SIGNAL_EXECUTION_FAILED_NO_EQUITY, // No Equity for Trade + X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR, // Price Error + X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR, // Prev Profit Error + X_SIGNAL_EXECUTION_FAILED_MAX_REACHED, // Max Allowed Positions Reached + X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED, // Same Positions Delay Not Passed + X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS, // Invalid Params +}; + +// +enum ENUM_X_POSITION_TYPES +{ + X_POSITION_TYPE_NONE = 0, + X_POSITION_TYPE_ALL = 1, + X_POSITION_TYPE_LONG = 2, + X_POSITION_TYPE_SHORT = 3, +}; + +// +bool IsValid(ENUM_X_POSITION_TYPES value) +{ + return value != X_POSITION_TYPE_NONE; +} +bool IsXValid(ENUM_X_POSITION_TYPES value) +{ + return IsValid(value); +} + +// +bool HasSpecifiedType(ENUM_X_POSITION_TYPES value) +{ + // + return value == X_POSITION_TYPE_LONG || + value == X_POSITION_TYPE_SHORT; +} + +// +string ToString(ENUM_X_POSITION_TYPES value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_POSITION_TYPE_ALL: + result = "All"; + break; + + // + case X_POSITION_TYPE_NONE: + result = "NONE"; + break; + + // + case X_POSITION_TYPE_SHORT: + result = "Short"; + break; + + // + case X_POSITION_TYPE_LONG: + result = "Long"; + break; + } + + // + return result; +} +string ToXString(ENUM_X_POSITION_TYPES value) +{ + return ToString(value); +} + +// +bool IsLong(ENUM_X_POSITION_TYPES value) +{ + return value == X_POSITION_TYPE_LONG; +} + +// +bool IsShort(ENUM_X_POSITION_TYPES value) +{ + return value == X_POSITION_TYPE_SHORT; +} + +// +bool ToPositionType( + ENUM_POSITION_TYPE &dest, + ENUM_X_POSITION_TYPES source // +) +{ + // + bool result = false; + + // + result = source == X_POSITION_TYPE_LONG || + source == X_POSITION_TYPE_SHORT; + if (!result) + { + return result; + } + + // + dest = + source == X_POSITION_TYPE_LONG + ? POSITION_TYPE_BUY + : POSITION_TYPE_SELL; + + // + return result; +} + +// +ENUM_X_POSITION_TYPES ToPositionType(ENUM_POSITION_TYPE value) +{ + return IsLong(value) + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_SHORT; +} + +// +ENUM_X_POSITION_TYPES OppositPositionType(ENUM_POSITION_TYPE type) +{ + // + ENUM_X_POSITION_TYPES result = X_POSITION_TYPE_NONE; + + // + bool isLong = IsLong(type); + bool isShort = IsShort(type); + + // + result = + // + isLong + ? X_POSITION_TYPE_SHORT + : isShort + ? X_POSITION_TYPE_LONG + : X_POSITION_TYPE_NONE + // + ; + + // + return result; +} + +// +ENUM_X_DIRECTION ToDirection(ENUM_POSITION_TYPE value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + result = IsLong(value) + ? X_DIRECTION_BULLISH + : X_DIRECTION_BEARISH; + + // + return result; +} + +// +ENUM_X_DIRECTION ToDirection(ENUM_X_POSITION_TYPES value) +{ + // + ENUM_X_DIRECTION result = X_DIRECTION_NONE; + + // + result = value == X_POSITION_TYPE_ALL + ? X_DIRECTION_ALL + : value == X_POSITION_TYPE_LONG + ? X_DIRECTION_BULLISH + : value == X_POSITION_TYPE_SHORT + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + + // + return result; +} + +// +// All Awailable Trade Restrictions ... +enum ENUM_XTRADE_RESTRICTION_PERIOD +{ + XTRADE_RESTRICATION_NONE, // None + XTRADE_RESTRICATION_HOURLY, // Per Hour + XTRADE_RESTRICATION_DAILY, // Per Day + XTRADE_RESTRICATION_WEEKLY, // Per Week + XTRADE_RESTRICATION_MONTHLY, // Per Month +}; + +// +string ToXString(ENUM_XTRADE_RESTRICTION_PERIOD value) +{ + // + string result = NULL; + + // + result = EnumToString(value); + + // + return result; +} + +// +ENUM_XTRADE_RESTRICTION_PERIOD ToXRestrictionPeriod(string value) +{ + // + ENUM_XTRADE_RESTRICTION_PERIOD result = XTRADE_RESTRICATION_NONE; + + // + if (!IsSpecifiedValid(value)) + { + return result; + } + + // + // None ... + if (value == ToXString(XTRADE_RESTRICATION_NONE)) + { + result = XTRADE_RESTRICATION_NONE; + } + // + // Per Hour ... + else if (value == ToXString(XTRADE_RESTRICATION_HOURLY)) + { + result = XTRADE_RESTRICATION_HOURLY; + } + // + // Per Day ... + else if (value == ToXString(XTRADE_RESTRICATION_DAILY)) + { + result = XTRADE_RESTRICATION_DAILY; + } + // + // Per Week ... + else if (value == ToXString(XTRADE_RESTRICATION_WEEKLY)) + { + result = XTRADE_RESTRICATION_WEEKLY; + } + // + // Per Month ... + else if (value == ToXString(XTRADE_RESTRICATION_MONTHLY)) + { + result = XTRADE_RESTRICATION_MONTHLY; + } + + // + return result; +} + +// +int GetXRestrictionsPeriodSeconds(ENUM_XTRADE_RESTRICTION_PERIOD value) +{ + // + int result = 0; + + // + if (!HasRestrictions(value)) + { + return result; + } + + // + switch (value) + { + // + // None ... + case XTRADE_RESTRICATION_NONE: + result = 0; + break; + + // + // Hour ... + case XTRADE_RESTRICATION_HOURLY: + result = PeriodSeconds(PERIOD_H1); + break; + + // + // Dayly ... + case XTRADE_RESTRICATION_DAILY: + result = PeriodSeconds(PERIOD_D1); + break; + + // + // Weekly ... + case XTRADE_RESTRICATION_WEEKLY: + result = PeriodSeconds(PERIOD_W1); + break; + + // + // Monthly ... + case XTRADE_RESTRICATION_MONTHLY: + result = PeriodSeconds(PERIOD_M1); + break; + } + + // + return result; +} + +/** + * Check a Value Has Trade Restrictions or not ... + * + * @param value: ENUM_XTRADE_RESTRICTION_PERIOD + * Ù‘ + * @return ( bool ) + */ +bool HasRestrictions(ENUM_XTRADE_RESTRICTION_PERIOD value) +{ + return value != XTRADE_RESTRICATION_NONE; +} + +// +// All Awailable Trade Finalizations ... +enum ENUM_XTRADE_FINALIZATION +{ + XTRADE_FINAL_NONE, // None + XTRADE_FINAL_TP, // TP + XTRADE_FINAL_SL, // SL + XTRADE_FINAL_CLOSE_IN_PROFIT, // Profit + XTRADE_FINAL_CLOSE_IN_LOSE, // Lost +}; + +// +string ToXString(ENUM_XTRADE_FINALIZATION value) +{ + return EnumToString(value); +} + +// +// Position Selecting Methods ... +enum ENUM_XPOSITION_SELECT_TYPES +{ + XPOSITION_SELECT_NONE = 0, // None + XPOSITION_SELECT_ALL = 1, // All + XPOSITION_SELECT_IN_PROFITS = 2, // In Profit Positions + XPOSITION_SELECT_IN_DRAWDOWNS = 3, // In Drawdown Positions + XPOSITION_SELECT_OLDEST = 4, // Oldest Position + XPOSITION_SELECT_YOUNGEST = 5, // Youngest Position + XPOSITION_SELECT_IN_PROFITS_OLDEST = 6, // In Profit Positions Oldest one + XPOSITION_SELECT_IN_PROFITS_YOUNGEST = 7, // In Profit Positions Youngest one + XPOSITION_SELECT_IN_PROFITS_MIN = 8, // Minimum Profitable Position + XPOSITION_SELECT_IN_PROFITS_MAX = 9, // Maximum Profitable Position + XPOSITION_SELECT_IN_DRAWDOWN_OLDEST = 10, // In Drawdown Positions Oldest one + XPOSITION_SELECT_IN_DRAWDOWN_YOUNGEST = 11, // In Drawdown Positions Youngest one + XPOSITION_SELECT_IN_DRAWDOWN_MIN = 12, // Minimum in Drawdown Position + XPOSITION_SELECT_IN_DRAWDOWN_MAX = 13, // Maximum in Drawdown Position + XPOSITION_SELECT_SAMES = 14, // Same Type Positions + XPOSITION_SELECT_SAMES_OLDEST = 15, // Same Type Positions Oldest one + XPOSITION_SELECT_SAMES_YOUNGEST = 16, // Same Type Positions Youngest one + XPOSITION_SELECT_OPPOSITS = 17, // Opposit Type Positions + XPOSITION_SELECT_OPPOSIT_OLDEST = 18, // Opposit Type Positions Oldest one + XPOSITION_SELECT_OPPOSIT_YOUNGEST = 19, // Opposit Type Positions Youngest one + XPOSITION_SELECT_SAME_IN_PROFITS = 20, // Same Type In Profit Positions + XPOSITION_SELECT_SAME_IN_PROFITS_OLDEST = 21, // Same Type In Profit Positions Oldest one + XPOSITION_SELECT_SAME_IN_PROFITS_YOUNGEST = 22, // Same Type In Profit Positions Youngest one + XPOSITION_SELECT_SAME_IN_PROFITS_MIN = 23, // Minimum Profitable of Same Type Positions + XPOSITION_SELECT_SAME_IN_PROFITS_MAX = 24, // Maximum Profitable of Same Type Positions + XPOSITION_SELECT_OPPOSIT_IN_PROFITS = 25, // Opposit Type In Profit Positions + XPOSITION_SELECT_OPPOSIT_IN_PROFITS_OLDEST = 26, // Opposit Type In Profit Positions Oldest one + XPOSITION_SELECT_OPPOSIT_IN_PROFITS_YOUNGEST = 27, // Opposit Type In Profit Positions Youngest one + XPOSITION_SELECT_OPPOSIT_IN_PROFITS_MIN = 28, // Minimum Profitable of Opposit Type Positions + XPOSITION_SELECT_OPPOSIT_IN_PROFITS_MAX = 29, // Maximum Profitable of Opposit Type Positions + XPOSITION_SELECT_SAME_IN_DRAWDOWNS = 30, // Same Type In Deawdown Positions + XPOSITION_SELECT_SAME_IN_DRAWDOWN_OLDEST = 31, // Same Type In Deawdown Positions Oldest one + XPOSITION_SELECT_SAME_IN_DRAWDOWN_YOUNGEST = 32, // Same Type In Deawdown Positions Youngest one + XPOSITION_SELECT_SAME_IN_DRAWDOWN_MIN = 33, // Minimum In Drawdown of Same Type Positions + XPOSITION_SELECT_SAME_IN_DRAWDOWN_MAX = 34, // Maximum In Drawdown of Same Type Positions + XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWNS = 35, // Opposit Type In Deawdown Positions + XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_OLDEST = 36, // Opposit Type In Deawdown Positions Oldest one + XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_YOUNGEST = 37, // Opposit Type In Deawdown Positions Youngest one + XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MIN = 38, // Minimum In Drawdown of Opposit Type Positions + XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MAX = 39, // Maximum In Drawdown of Opposit Type Positions +}; + +/** + * Validate Position Select Type ... + * + * @param value: ENUM_XPOSITION_SELECT_TYPES + * + * @return ( bool ) + */ +bool IsXValid(ENUM_XPOSITION_SELECT_TYPES value) +{ + return value != XPOSITION_SELECT_NONE; +} + +// +string ToXString(ENUM_XPOSITION_SELECT_TYPES value) +{ + return EnumToString(value); +} + +// +// Structs ... + +// +struct XRR +{ + // + double tps[]; + + // + double sl; + double entry; + + // + string prefix; + string symbol; + datetime time; + ENUM_TIMEFRAMES period; + + // + ENUM_X_POSITION_TYPES type; + + // + // Constructor ... + XRR() + { + Clean(); + } + + // + // Tools ... + + // + void Clean() + { + // + sl = 0; + entry = 0; + + // + time = NULL; + prefix = NULL; + period = NULL; + symbol = NULL; + + // + type = X_POSITION_TYPE_NONE; + + // + SpecifiedClean(tps); + + // + ZeroMemory(this); + } + + // + bool Init( + string _symbol, + ENUM_TIMEFRAMES _period, + double _sl, + double _entry, + ENUM_X_POSITION_TYPES _type, + string _prefix = NULL // + ) + { + // + bool result = false; + + // + result = + _sl > 0 && + _entry > 0 && + IsSpecifiedValid(_symbol) && + IsSpecifiedValid(_period) && + _type != X_POSITION_TYPE_ALL && + _type != X_POSITION_TYPE_NONE && + (_type == X_POSITION_TYPE_LONG + ? _entry > _sl + : _entry < _sl); + if (!result) + { + return result; + } + + // + Default(); + + // + sl = _sl; + type = _type; + entry = _entry; + symbol = _symbol; + period = _period; + prefix = _prefix; + + // + time = TimeCurrent(); + + // + result = IsValid(); + + // + return result; + } + + // + void Default() + { + // + Add( + 1.0, + tps // + ); + Add( + 1.5, + tps // + ); + Add( + 2.0, + tps // + ); + Add( + 3.0, + tps // + ); + Add( + 4.0, + tps // + ); + Add( + 5.0, + tps // + ); + Add( + 6.0, + tps // + ); + } + + // + bool IsValid() + { + // + bool result = false; + + // + result = + sl > 0 && + entry > 0 && + IsSpecifiedValid(time) && + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period) && + IsValidSize(ArraySize(tps)) && + type != X_POSITION_TYPE_ALL && + type != X_POSITION_TYPE_NONE && + (type == X_POSITION_TYPE_LONG + ? entry > 0 + : entry < sl); + + // + return result; + } + + // + string GetTag() + { + // + string result = NULL; + + // + if (!IsValid()) + { + // + result = GetTypeName(this); + return result; + } + + // + string sep = "_"; + + // + result = + GetTypeName(this) + sep + (IsSpecifiedValid(prefix) ? prefix + sep : "") + symbol + sep + ToXString(period) + sep + ToFormatString(time) + sep + ToString(type); + + // + return result; + } +}; + +// +// Model a Target ... +struct XTarget +{ + // + // Props ... + bool doRF; // Do RF on Target + bool doRFOnEntry; // Do RF on Entry + double actingDistance; // Acting Distances + double target; // Target Price for Actions + double volumeMultiplier; // Volume Multiplier for Partial Close + double tpValue; // TP Value Changed ... + + // + // Constructor ... + XTarget() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + target = 0; + tpValue = 0; + doRF = false; + actingDistance = 0; + doRFOnEntry = false; + volumeMultiplier = 0; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = target > 0; + + // + return result; + } +}; + +// +// Get Lowest Target index ... +int GetLowest(XTarget &targets[]) +{ + // + int result = -1; + + // + if (!HasChild(targets)) + { + return result; + } + + // + XTarget iTarget; + int count = ArraySize(targets); + for (int i = 0; i < count; i++) + { + // + bool canSet = + !iTarget.IsValid() + ? true + : iTarget.target > targets[i].target; + if (canSet) + { + // + result = i; + iTarget = targets[i]; + } + } + + // + iTarget.Clean(); + + // + return result; +} + +// +// Get Highest Target index ... +int GetHighest(XTarget &targets[]) +{ + // + int result = -1; + + // + if (!HasChild(targets)) + { + return result; + } + + // + XTarget iTarget; + int count = ArraySize(targets); + for (int i = 0; i < count; i++) + { + // + bool canSet = + !iTarget.IsValid() + ? true + : iTarget.target < targets[i].target; + if (canSet) + { + // + result = i; + iTarget = targets[i]; + } + } + + // + iTarget.Clean(); + + // + return result; +} + +// +// Apply Sorting on Targets ... +void ApplySortOnTargets( + ENUM_X_DIRECTION forDir, // Target Sorting Direction ... + XTarget &targets[] // Targets to Apply Sorting ... +) +{ + // + bool has = HasChild(targets) && + HasDirection(forDir); + if (!has) + { + return; + } + + // + bool isBullish = IsBullish(forDir); + bool isBearish = IsBearish(forDir); + + // + XTarget tmp[]; + Copy( + targets, + tmp // + ); + Clean(targets); + while (HasChild(tmp)) + { + // + int idx = -1; + if (isBullish) + { + idx = GetLowest(tmp); + } + else if (isBearish) + { + idx = GetHighest(tmp); + } + + // + has = IsValidIndex(idx); + if (!has) + { + break; + } + + // + XTarget iTarget = tmp[idx]; + ArrayRemove( + tmp, + idx, + 1 // + ); + AddRef( + iTarget, + targets // + ); + } + + // + Clean(tmp); +} + +// +// Model an Open Position ... +struct XPosition +{ + // + // Props ... + + // + // Magic Number ... + ulong magic; + + // + // Ticket ID ... + ulong ticket; + + // + // Tradinng Symbol ... + string symbol; + + // + // Trading Period ... + ENUM_TIMEFRAMES period; + + // + // Position Type ... + ENUM_POSITION_TYPE type; + + // + // Take Profit ... + double tp; + + // + // Stop Loss ... + double sl; + + // + // Position Current Profit ... + double profit; + + // + // Position Open Price ... + double entry; + + // + // Current Symbol Price ... + double price; + + // + // Position Swap ... + double swap; + + // + // Position Commission ... + double commission; + + // + // Volume ... + double volume; + + // + // Position Open Time ... + datetime openAt; + + // + // Sifnal Provider ... + string provider; + + // + // Position Comment ... + string comment; + + // + // Constructor ... + XPosition() + { + Clean(); + } + + // + // Initializers ... + + bool ByIndex(int index) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + ulong mTicket = mPositionInfo.Ticket(); + + // + result = ByTicket(mTicket); + + // + return result; + } + + bool ByTicket(ulong mTicket) + { + // + bool result = false; + + // + static CPositionInfo mPositionInfo; + + // + result = mPositionInfo.SelectByTicket(mTicket); + if (!result) + { + return result; + } + + // + swap = mPositionInfo.Swap(); + magic = mPositionInfo.Magic(); + openAt = mPositionInfo.Time(); + sl = mPositionInfo.StopLoss(); + ticket = mPositionInfo.Ticket(); + symbol = mPositionInfo.Symbol(); + tp = mPositionInfo.TakeProfit(); + profit = mPositionInfo.Profit(); + volume = mPositionInfo.Volume(); + comment = mPositionInfo.Comment(); + entry = mPositionInfo.PriceOpen(); + type = mPositionInfo.PositionType(); + price = mPositionInfo.PriceCurrent(); + commission = mPositionInfo.Commission(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + magic = 0; + ticket = 0; + tp = 0; + sl = 0; + swap = 0; + entry = 0; + price = 0; + profit = 0; + volume = 0; + openAt = 0; + commission = 0; + + // + type = NULL; + period = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsSpecifiedValid(symbol) && + NotEmpty(ticket) + // + ; + + // + return result; + } + + // + bool IsLong() + { + return IsValid() && + IsXBullish(type); + } + + // + bool IsBullish() + { + return IsLong(); + } + + // + bool IsShort() + { + return IsValid() && + IsXBearish(type); + } + + // + bool IsBearish() + { + return IsShort(); + } + + // + ENUM_X_DIRECTION GetDirection() + { + // + return IsBullish() + ? X_DIRECTION_BULLISH + : IsBearish() + ? X_DIRECTION_BEARISH + : X_DIRECTION_NONE; + } + + // + // Retrieve Entry Price ... + double GetEntry() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetXEntry( + symbol, + type + // + ); + + // + return result; + } + + // + // Retrieve Exit ... + double GetExit() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetXExit( + symbol, + type + // + ); + + // + return result; + } + + // + // Get Spread by Point ... + double GetSpread() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = PriceToPoint(GetXSpread(symbol)); + + // + return result; + } + + // + double GetPointsValue() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetPoints(symbol); + + // + return result; + } + + // + double GetProfitInPoint() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + double tickSize = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE); // Tick size + double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); // Tick value + double pointSize = SymbolInfoDouble(symbol, SYMBOL_POINT); // Point size + double pointValue = tickValue * pointSize / tickSize; // Point value + + // + result = profit / (volume * tickValue); + + // + return result; + } + + // + // Find Risk ... + double GetRisk() + { + // + double result = 0; + + // + if (!IsValid()) + { + return 0; + } + + // + result = MathAbs(entry - sl); + + // + return result; + } + + // + double GetRiskInPoint() + { + // + double result = 0; + + // + result = GetRisk() / GetPoints(); + + // + return result; + } + + // + // Find Reward ... + double GetReward() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathAbs(tp - entry); + + // + return result; + } + + // + double GetRewardInPoint() + { + // + double result = 0; + + // + result = GetReward() / GetPoints(); + + // + return result; + } + + // + // Find Risk Reward Ratio ... + double GetRiskRewardRatio() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetReward() / GetRisk(); + + // + return result; + } + + // + // Calculate TP Levels ... + int CalculateTPLevels(double &tps[]) + { + + // + int result = 0; + + // + SpecifiedClean(tps); + + // + bool isValid = IsValid(); + if (!isValid) + { + return result; + } + + // + double risk = GetRisk(); + int r2r = (int)GetRiskRewardRatio(); + bool isLong = IsLong(); + for (int i = 0; i < r2r; i++) + { + // + double iValue = + isLong + ? entry + risk + (i * risk) + : entry - risk - (i * risk); + // + Add( + iValue, + tps // + ); + } + + // + result = ArraySize(tps); + + // + return result; + } + + // + // Calculate Reached TP Levels ... + void CalculateReahedTP( + double &reachedLevel, + double &reachedPrice // + ) + { + // + reachedLevel = -1; + reachedPrice = 0; + double tps[]; + bool isLong = IsLong(); + double exitPrice = GetExit(); + int tpLevels = CalculateTPLevels(tps); + if (!IsValidSize(tpLevels) || exitPrice <= 0) + { + return; + } + + // + for (int i = 0; i < tpLevels - 1; i++) + { + // + double cTP = tps[i]; + double nTP = tps[i + 1]; + + // + bool isReached = + isLong + ? exitPrice > cTP && + exitPrice < nTP + : exitPrice < cTP && + exitPrice > nTP; + if (isReached) + { + // + reachedLevel = i + 1; + reachedPrice = cTP; + } + } + } + + // + // Calculate Touched Reward ... + double CalculateTouchedReward() + { + // + double result = 0.0; + + // + bool has = IsValid() && + profit > 0; + if (!has) + { + return result; + } + + // + double risk = MathAbs(entry - sl); + double currentReward = MathAbs(price - entry); + + // + result = currentReward / risk; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetXAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XPosition &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + XPosition &values[] // Collection to Find + ) + { + // + return FindXIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell) + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Signal ... +struct XSignal +{ + // + // Props ... + + // + ulong positionId; // if Executed this filled ... + + // + datetime time; // Issue Time ... + + // + double tp; // Take Profit ... + double sl; // Stop Loss ... + double entry; // Exntry or Execution Price ... + double volume; // Position Volume ... + + // + string symbol; // Trading Symbol ... + string comment; // Comment ... + string provider; // Signaller ... + + // + ENUM_TIMEFRAMES period; // Trading TimeFrame ... + ENUM_POSITION_TYPE type; // Long (Buy) or Short (Sell) ... + ENUM_X_ORDER_MODES mode; // Execution Mode ... + + // + string conditions; // Signal Conditions ... + + // + // Additional ... + + // + // Traget ... + XTarget targets[]; // Provided Targets ... + int appliedTargetIDX; // Last Applied Target Index ... + bool ignoreEAVolume; // Ignore EA Volume ... + bool isTargetApplied; // Check if Target Applied or not ... + + // + // Constructor ... + XSignal() + { + Default(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + entry = 0; + volume = 0; + positionId = 0; + + // + time = NULL; + type = NULL; + mode = NULL; + symbol = NULL; + period = NULL; + comment = NULL; + provider = NULL; + conditions = NULL; + + // + SpecifiedClean(targets); + appliedTargetIDX = -1; + ignoreEAVolume = false; + isTargetApplied = false; + + // + ZeroMemory(this); + } + + // + // Default Values ... + void Default() + { + // + entry = 0; + volume = 0; + positionId = 0; + + // + time = NULL; + type = NULL; + mode = NULL; + symbol = NULL; + period = NULL; + comment = NULL; + provider = NULL; + conditions = NULL; + + // + SpecifiedClean(targets); + appliedTargetIDX = -1; + ignoreEAVolume = false; + isTargetApplied = false; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsSpecifiedValid(period) && + IsSpecifiedValid(symbol) && + NotEmpty(volume) && + NotEmpty(entry) + // + ; + + // + if (!result) + { + return result; + } + + // + return result; + } + + // + // DO All Calculations and Normalizations ... + bool Normalize() + { + // + bool result = false; + + // + // Normalizations ... + symbol = NormalizeSymbol(symbol); + period = NormalizePeriod(period); + + // + time = NormalizeTime(time); + + // + sl = NormalizePrice(sl, symbol); + tp = NormalizePrice(tp, symbol); + entry = NormalizePrice(entry, symbol); + volume = NormalizeVolume(volume, symbol); + + // + result = IsValid(); + + // + return result; + } + + // + // Check Signal Executed or not ... + bool IsExecuted() + { + // + bool result = false; + + // + result = + // + IsValid() && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Generate Comment for Signal ... + string GenerateComment() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + if (IsSpecifiedValid(provider)) + { + // + // Generate Provider Tag ... + result += GenerateProviderTag(provider); + } + + // + if (IsSpecifiedValid(period)) + { + // + // Generate Period Tag ... + result += GeneratePeriodTag(period); + } + + // + return result; + } + + // + int GetAge() + { + // + return GetXAge( + this, + this.period // + ); + } + + // + // Find Risk ... + double GetRisk() + { + // + double result = 0; + + // + if (!IsValid()) + { + return 0; + } + + // + result = MathAbs(entry - sl); + + // + return result; + } + + // + // Find Reward ... + double GetReward() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = MathAbs(tp - entry); + + // + return result; + } + + // + // Find Risk Reward Ratio ... + double GetRiskRewardRatio() + { + // + double result = 0; + + // + if (!IsValid()) + { + return result; + } + + // + result = GetReward() / GetRisk(); + + // + return result; + } + + // + string GetTag() + { + // + string result = NULL; + + // + result = "XSignal_" + + symbol + "_" + + ToXString(period) + "_" + + ToXString(type) + "_" + + ToXString(sl) + "_" + + ToXString(tp) + "_" + + ToXString(entry); + + // + return result; + } + + // + string GetObjectID() + { + // + string result = ""; + + // + if (!IsValid()) + { + return result; + } + + // + result = "XSignal_" + + symbol + "_" + + ToXString(period) + "_" + + ToXString(type) + "_" + + ToXString(TimeToSeconds(time)); + + // + return result; + } + + // + // Retrieve String Representation of Signal ... + string ToString() + { + // + string result = NULL; + + // + result = + // + ToXString("Symbol", symbol) + + ToXString("Period", period) + + ToXString("Provider", provider) + + ToXString("Type", type) + + ToXString("Mode", mode) + + ToXString("Volume", volume) + + ToXString("Entry", entry) + + ToXString("TP", tp) + + ToXString("SL", sl) + + ToXString("Time", time) + + ToXString("Comment", comment) + + // + "" + // + ; + + // + return result; + } + + // + bool IsSameAs(XSignal &item) + { + // + bool result = false; + + // + result = + // + IsValid() && + item.IsValid() && + // + tp == item.tp && + sl == item.sl && + mode == item.mode && + time == item.time && + type == item.type && + entry == item.entry && + symbol == item.symbol && + period == item.period && + provider == item.provider + // + ; + + // + return result; + } + + // + string GetMessage(string action = NULL) + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + result = ToXString(type) + + " Signal" + + (!IsSpecifiedValid(action) + ? "" + : " " + action) + + " by: " + provider + + " on (" + symbol + ")" + + " in: " + ToXString(period); + + // + return result; + } + + // + string GetFileName() + { + // + string result = NULL; + + // + if (!IsValid()) + { + return result; + } + + // + result = + // + symbol + "\\" + + ToXString(type) + "\\" + + ToXString(period) + "_" + + ToFormatString(time) + // + ; + + // + return result; + } +}; + +// +// Model an Order ... +struct XOrder +{ + // + // Time of order placement ... + datetime setupAt; + + // + // Time of order expiration ... + datetime expiredAt; + + // + // Time of order execution or cancellation ... + datetime executedAt; + + // + // Order type ... + ENUM_ORDER_TYPE type; + + // + // Order state ... + ENUM_ORDER_STATE state; + + // + // Type of execution by remainder ... + ENUM_ORDER_TYPE_FILLING filling; + + // + // Order lifetime ... + ENUM_ORDER_TYPE_TIME lifetime; + + // + // Order ticket ... + ulong ticket; + + // + // Magic Number ... + long magic; + + // + // Position id, that is placed on order, + // when it is executed. Each executed order invokes a + // deal, that opens new or changes existing + // position. Id of that position is placed on + // executed order in this moment. + long positionId; + + // + // Initial volume on order placement ... + double initialVolume; + + // + // Unfilled volume ... + double currentVolume; + + // + // Price, specified in the order ... + double openPrice; + + // + // Current price by order symbol ... + double currentPrice; + + // + // Price of placing Limit order when StopLimit order is triggered ... + double stopLimitPrice; + + // + // Take Profit level ... + double tp; + + // + // Stop Loss level ... + double sl; + + // + // Trading Symbol ... + string symbol; + + // + // Signal Provider ... + string provider; + + // + // Order Comment ... + string comment; + + // + ENUM_TIMEFRAMES period; + + // + // Constructor ... + XOrder() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = OrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static COrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Retrieve Specific History Order ... + bool HistoryByIndex( + int index // Fill By Index ... + ) + { + // + bool result = false; + + // + int ordersCount = HistoryOrdersTotal(); + if (ordersCount <= 0) + { + return result; + } + + // + static CHistoryOrderInfo mOrderInfo; + + // + result = mOrderInfo.SelectByIndex(index); + if (!result) + { + return result; + } + + // + // Reading Order Info ... + magic = mOrderInfo.Magic(); + sl = mOrderInfo.StopLoss(); + tp = mOrderInfo.TakeProfit(); + ticket = mOrderInfo.Ticket(); + openPrice = mOrderInfo.PriceOpen(); + positionId = mOrderInfo.PositionId(); + currentPrice = mOrderInfo.PriceCurrent(); + initialVolume = mOrderInfo.VolumeInitial(); + currentVolume = mOrderInfo.VolumeCurrent(); + stopLimitPrice = mOrderInfo.PriceStopLimit(); + + // + symbol = mOrderInfo.Symbol(); + comment = mOrderInfo.Comment(); + + // + state = mOrderInfo.State(); + type = mOrderInfo.OrderType(); + lifetime = mOrderInfo.TypeTime(); + filling = mOrderInfo.TypeFilling(); + + // + setupAt = mOrderInfo.TimeSetup(); + executedAt = mOrderInfo.TimeDone(); + expiredAt = mOrderInfo.TimeExpiration(); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + tp = 0; + sl = 0; + magic = 0; + ticket = 0; + positionId = 0; + openPrice = 0; + currentPrice = 0; + initialVolume = 0; + currentVolume = 0; + stopLimitPrice = 0; + + // + setupAt = NULL; + expiredAt = NULL; + executedAt = NULL; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + state = NULL; + period = NULL; + filling = NULL; + lifetime = NULL; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsSpecifiedValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetXAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XOrder &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + state == value.state && + magic == value.magic && + ticket == value.ticket && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + XOrder &values[] // Collection to Find + ) + { + // + return FindXIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_X_POSITION_TYPES mType = NULL, // Long (Buy), Short (Sell) + ENUM_ORDER_STATE mState = NULL, // Order State + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // State Filter ... + IsStateFilterPassed( + mState, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model a Deal ... +struct XDeal +{ + // + // the ID of the Expert Advisor, that executed the deal ... + ulong magic; + + // + // the ID of position, in which the deal was involved ... + ulong positionId; + + // + // Ticket ... + ulong ticket; + + // + // the name of the deal symbol ... + string symbol; + + // + // order by which the deal is executed ... + ulong order; + + // + // the time of deal execution ... + datetime time; + + // + // Deal price ... + double price; + + // + // the financial result of the deal (in deposit currency) ... + double profit; + + // + // the amount of swap when position is closed ... + double swap; + + // + // the amount of commission of the deal ... + double commission; + + // + // the volume of deal ... + double volume; + + // + // the deal comment ... + string comment; + + // + string provider; + + // + ENUM_TIMEFRAMES period; + + // + // the deal type ... + // ------------------------------------------------------------------ + // DEAL_TYPE_BUY => Buy ... + // DEAL_TYPE_SELL => Sell ... + // DEAL_TYPE_BUY_CANCELED => Canceled buy deal ... + // There can be a situation when a previously executed buy deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_BUY) is changed to DEAL_TYPE_BUY_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation ... + // + // DEAL_TYPE_SELL_CANCELED => Canceled sell deal ... + // There can be a situation when a previously executed sell deal is canceled. In this case, + // the type of the previously executed deal (DEAL_TYPE_SELL) is changed to DEAL_TYPE_SELL_CANCELED, + // and its profit/loss is zeroized. Previously obtained profit/loss is charged/withdrawn using a separated balance operation + // + // DEAL_TYPE_BALANCE => Balance ... + // DEAL_TYPE_CREDIT => Credit ... + // DEAL_TYPE_CHARGE => Additional charge ... + // DEAL_TYPE_CORRECTION => Correction ... + // DEAL_TAX => Tax charges ... + // DEAL_TYPE_BONUS => Bonus ... + // DEAL_TYPE_INTEREST => Interest rate ... + // DEAL_DIVIDEND => Dividend operations... + // DEAL_DIVIDEND_FRANKED => Franked (non-taxable) dividend operations ... + // DEAL_TYPE_COMMISSION => Additional commission ... + // DEAL_TYPE_COMMISSION_DAILY => Daily commission ... + // DEAL_TYPE_COMMISSION_MONTHLY => Monthly commission ... + // DEAL_TYPE_COMMISSION_AGENT_DAILY => Daily agent commission ... + // DEAL_TYPE_COMMISSION_AGENT_MONTHLY => Monthly agent commission + ENUM_DEAL_TYPE type; + + // + // the deal direction ... + // ---------------------------------- + // DEAL_ENTRY_IN => Entry in ... + // DEAL_ENTRY_OUT => Entry out ... + // DEAL_ENTRY_INOUT => Reverse ... + // DEAL_ENTRY_OUT_BY => Close a position by an opposite one ... + ENUM_DEAL_ENTRY entry; + + // + // deal reson ... + // --------------------- + // DEAL_REASON_SL => The deal was executed as a result of Stop Loss activation ... + // DEAL_REASON_TP => The deal was executed as a result of Take Profit activation ... + // DEAL_REASON_SO => The deal was executed as a result of the Stop Out event ... + // DEAL_REASON_WEB => The deal was executed as a result of activation of an order placed from the web platform ... + // DEAL_REASON_SPLIT => The deal was executed after the split (price reduction) of an instrument, which had an open position during split announcement ... + // DEAL_REASON_CLIENT => The deal was executed as a result of activation of an order placed from a desktop terminal ... + // DEAL_REASON_MOBILE => The deal was executed as a result of activation of an order placed from a mobile application ... + // DEAL_REASON_EXPERT => The deal was executed as a result of activation of an order placed from an MQL5 program, i.e. an Expert Advisor or a script ... + // DEAL_REASON_VMARGIN => The deal was executed after charging the variation margin ... + // DEAL_REASON_ROLLOVER => The deal was executed due to a rollover ... + ENUM_DEAL_REASON reason; + + // + // Constructor ... + XDeal() + { + Clean(); + } + + // + // Initializers ... + bool ByIndex( + int index // Deal Index + ) + { + // + bool result = false; + + // + int dealsCount = HistoryDealsTotal(); + result = dealsCount > 0; + if (!result) + { + return result; + } + + // + static CDealInfo mDealInfo; + + // + result = mDealInfo.SelectByIndex(index); + if (!result) + { + // + return result; + } + + // + // Reading Order Info ... + swap = mDealInfo.Swap(); + magic = mDealInfo.Magic(); + order = mDealInfo.Order(); + ticket = mDealInfo.Ticket(); + time = mDealInfo.Time(); + price = mDealInfo.Price(); + symbol = mDealInfo.Symbol(); + profit = mDealInfo.Profit(); + volume = mDealInfo.Volume(); + comment = mDealInfo.Comment(); + positionId = mDealInfo.PositionId(); + entry = mDealInfo.Entry(); + commission = mDealInfo.Commission(); + type = mDealInfo.DealType(); + reason = (ENUM_DEAL_REASON)HistoryDealGetInteger( + ticket, + DEAL_REASON); + + // + period = ExtractPeriod(comment); + provider = ExtractProvider(comment); + + // + result = IsValid(); + + // + return result; + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + magic = 0; + positionId = 0; + ticket = 0; + order = 0; + time = 0; + price = 0; + profit = 0; + swap = 0; + commission = 0; + volume = 0; + + // + symbol = NULL; + comment = NULL; + provider = NULL; + + // + type = NULL; + entry = NULL; + period = NULL; + reason = NULL; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + IsSpecifiedValid(symbol) && + NotEmpty(ticket) && + NotEmpty(positionId) + // + ; + + // + return result; + } + + // + // Calculate Age ... + int GetAge( + ENUM_TIMEFRAMES mPeriod // Calculate Age based on this period + ) + { + return GetXAge(this, mPeriod); + } + + // + // Check this instance is Same os Given instance or not ... + bool IsSameAs( + const XDeal &value // instance for Compare + ) + { + // + bool result = false; + + // + result = + // + type == value.type && + magic == value.magic && + entry == value.entry && + reason == value.reason && + ticket == value.ticket && + volume == value.volume && + symbol == value.symbol && + provider == value.provider && + positionId == value.positionId + // + ; + + // + return result; + } + + // + // Find index in a Collection ... + int FindIndex( + XDeal &values[] // Collection to Find + ) + { + // + return FindXIndex( + this, + values + // + ); + } + + // + // Check Items Passed Specific Filters or not ... + bool IsFiltersPassed( + string mSymbol = NULL, // Trading Symbol + string mProvider = NULL, // Signal Provider + ENUM_TIMEFRAMES mPeriod = NULL, // Trading Timeframe + ENUM_DEAL_TYPE mType = NULL, // Deal Type + ENUM_DEAL_ENTRY mEntry = NULL, // Deal Entry + ENUM_DEAL_REASON mReason = NULL, // Deal Reason + ulong mMagic = NULL, // Magic Number + bool mFilterByMagic = true // Get Only Self Open Positions + ) + { + // + bool result = false; + + // + result = + // + // Magic Filter ... + IsMagicFilterPassed( + mMagic, + mFilterByMagic, + this + // + ) + // + && + // + // Symbol Filter ... + IsSymbolFilterPassed( + mSymbol, + this + // + ) + // + && + // + // Provider Filter ... + IsProviderFilterPassed( + mProvider, + this + // + ) + // + && + // + // Period Filter ... + IsPeriodFilterPassed( + mPeriod, + this + // + ) + // + && + // + // Type Filter ... + IsTypeFilterPassed( + mType, + this + // + ) + // + && + // + // Entry Filter ... + IsEntryFilterPassed( + mEntry, + this + // + ) + // + && + // + // Reason Filter ... + IsReasonFilterPassed( + mReason, + this + // + ) + // + ; + + // + return result; + } +}; + +// +// Model OnTrade Event Handler Result on XCTrade Class ... +struct XOnTradeHandlerState +{ + // + bool hasNewDeal; + int newDeals; + + // + bool hasNewOrder; + int newOrders; + + // + bool hasNewPosition; + int newPositions; + + // + bool hasNewHistoryOrder; + int newHistoryOrders; + + // + // Constructor ... + XOnTradeHandlerState() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + hasNewDeal = false; + hasNewOrder = false; + hasNewPosition = false; + hasNewHistoryOrder = false; + + // + newDeals = 0; + newOrders = 0; + newPositions = 0; + newHistoryOrders = 0; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + // + ( + // + hasNewDeal + ? newDeals > 0 + : true + // + ) + // + && + // + ( + // + hasNewOrder + ? newOrders > 0 + : true + // + ) + // + && + // + ( + // + hasNewPosition + ? newPositions > 0 + : true + // + ) + // + && + // + ( + // + hasNewHistoryOrder + ? newHistoryOrders > 0 + : true + // + ) + // + ; + + // + return result; + } +}; + +// +// an Structure for Describe aTrading Session ... +struct XTradeSession +{ + // + // Properties ... + string start; // Session Start Time (hh:mm) + string end; // Session End Time (hh:mm) + string name; // Session Name + + // + // Constructor ... + XTradeSession() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + end = NULL; + name = NULL; + start = NULL; + + // + ZeroMemory(this); + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = IsSpecifiedValid(start) && + IsSpecifiedValid(end); + if (!result) + { + return result; + } + + // + return result; + } + + // + // Check Session is Active or Not ... + bool IsActive(datetime time = NULL) + { + // + bool result = false; + + // + time = NormalizeTime(time); + + // + result = IsValid(); + if (!result) + { + return result; + } + + // + result = IsTimeInRange( + time, + start, + end // + ); + + // + return result; + } +}; + +// +// an Structure for Describe an Specified Symbols +// Trading Sessions ... +struct XSymbolTradeConfig +{ + // + // Propeties ... + + // + int longs; // All Long Trades + int shorts; // All Short Trades + int trades; // All Trades + int losses; // All Loosing Trades + int profits; // All Winning Trades + string name; // Provider Name + string symbol; // Trading Symbol + int managedSLs; // Managed SL(s) + int managedTPs; // Managed TP(s) + int managedTrades; // Managed Trades + int maxAllowedTPs; // Max Allowed TP(s) in Restrictions Period + int maxAllowedSLs; // Max Allowed SL(s) in Restrictions Period + int maxAllowedTrades; // Max Allowed Trades in Restrictions Period + datetime managedStart; // Managed Start Time + double managedBalance; // Managed Start Balance + double managedProfits; // Managed Profit(s) + ENUM_TIMEFRAMES period; // Trading Period + int maxAllowedPositions; // Max Allowed Same Time Trades + double maxAllowedSpread; // Max Allowed Spread For Trade + bool isForceCloseAtTime; // a Flag for Determines Force Closed or not + XTradeSession sessions[]; // Trading Sessions + string closeAllOpenTradesAt; // Close All Open Trades per Day At Specified Time + int restrictionsPeriodMultiplier; // Specified Restrictions Period Multiplier + ENUM_XTRADE_RESTRICTION_PERIOD restrictionsPeriod; // Trade Restrictions Period + + // + // Constructor ... + XSymbolTradeConfig() + { + Clean(); + } + + // + // Tools ... + + // + // Cleanup ... + void Clean() + { + // + name = NULL; + symbol = NULL; + period = NULL; + SpecifiedClean(sessions); + + // + longs = 0; + shorts = 0; + trades = 0; + losses = 0; + profits = 0; + + // + managedStart = NULL; + + // + managedSLs = 0; + managedTPs = 0; + managedTrades = 0; + + // + managedBalance = 0; + managedProfits = 0; + + // + maxAllowedTPs = 0; + maxAllowedSLs = 0; + maxAllowedTrades = 0; + maxAllowedSpread = 25; + maxAllowedPositions = 5; + closeAllOpenTradesAt = ""; + isForceCloseAtTime = false; + restrictionsPeriod = XTRADE_RESTRICATION_NONE; + + // + ZeroMemory(this); + } + + /** + * Initial ... + * + * @param _symbol: Trading Symbol + * @param _period: Trading Period + * @param _sessionsDescriptor: Sessions Description + * @param _maxAllowedSpread: Max Allowed Spread for Open Trade + * @param _maxAllowedPositions: Max Allowed Same Time Position + * @param _restrictionsDescriptor: Restrictions Descriptor + * + * @return ( bool ) + */ + bool Init( + string _name, + string _symbol = NULL, + ENUM_TIMEFRAMES _period = NULL, + string _sessionsDescriptor = NULL, + double _maxAllowedSpread = 25, + int _maxAllowedPositions = 5, + string _restrictionsDescriptor = NULL // + ) + { + // + bool result = false; + + // + // Normalize Symbol ... + _symbol = NormalizeSymbol(_symbol); + _period = NormalizePeriod(_period); + + // + name = _name; + symbol = _symbol; + period = _period; + maxAllowedSpread = _maxAllowedSpread; + maxAllowedPositions = _maxAllowedPositions; + + // + // Parse Sessions ... + ParseSessions(_sessionsDescriptor); + + // + // Parse Restrictions ... + ParseRestrictions(_restrictionsDescriptor); + + // + // Check Validation ... + result = IsValid(); + + // + return result; + } + + // + // Check Same ... + bool IsSame(XSymbolTradeConfig &dest) + { + // + bool result = false; + + // + // Validate ... + result = IsValid() && + dest.IsValid() && + name == dest.name && + symbol == dest.symbol && + period == dest.period; + + // + return result; + } + + // + // Validate ... + bool IsValid() + { + // + bool result = false; + + // + result = + IsSpecifiedValid(name) && + IsSpecifiedValid(symbol) && + IsSpecifiedValid(period); + + // + return result; + } + + // + // Check Allow Trade in Active Sessions ... + bool CanTrade(datetime time = NULL) + { + // + bool result = false; + + // + // Normalize Args ... + time = NormalizeTime(time); + + // + // Validating ... + result = IsValid(); + if (!result) + { + return result; + } + + // + // if there is not any defined sessions for Symbol ... + // it's allow Trading in all times ... + result = !HasChild(sessions); + if (result) + { + return result; + } + + // + // Detect an Active Session ... + int count = ArraySize(sessions); + for (int i = 0; i < count; i++) + { + // + result = sessions[i].IsActive(time); + if (result) + { + break; + } + } + + // + return result; + } + + // + // Checking Restrictions ... + bool IsRestricted(datetime time = NULL) + { + // + bool result = false; + + // + // Normalize Time ... + time = NormalizeTime(time); + + // + // Check Has Restrictions ... + bool has = HasRestrictions(restrictionsPeriod); + result = !has; + if (result) + { + return result; + } + + // + // Check Restrictions Time ... + has = IsSpecifiedValid(managedStart) && + time <= managedStart; + result = !has; + if (result) + { + return result; + } + + // + // Validate Restrictions Timing ... + // Check Restrictions ... + + // + bool isTPAllowed = maxAllowedTPs == 0 + ? true + : managedTPs < maxAllowedTPs; + bool isSLAllowed = maxAllowedSLs == 0 + ? true + : managedSLs < maxAllowedSLs; + bool isTradeAllowed = maxAllowedTrades == 0 + ? true + : managedTrades < maxAllowedTrades; + + // + result = isTPAllowed && + isSLAllowed && + isTradeAllowed; + if (result) + { + return result; + } + + // + // Check Restrictions Reset ... + HandleRestrictions(); + + // + return result; + } + + // + // Parse Sessions ... + void ParseSessions(string descriptor) + { + // + // Validate ... + if (!IsSpecifiedValid(descriptor)) + { + return; + } + + // + bool has = false; + string _sessions[]; + int sessionsCount = 0; + + // + // Extract Per Symbol Sessions ... + sessionsCount = SplitContent( + _sessions, + descriptor, + "," // + ); + + // + // Try to Extract Start and End Times Series ... + has = IsValidSize(sessionsCount); + if (!has) + { + return; + } + + // + // Iterate Sessions ... + for (int i = 0; i < sessionsCount; i++) + { + // + // Ignore unused Cases and Extracts only Content ... + string iSessionDescriptorStr = ExtractString(_sessions[i]); + has = IsSpecifiedValid(iSessionDescriptorStr); + if (has) + { + // + // Extract Session Descriptor Data ... + string parts[]; + int partsCount = SplitContent( + parts, + iSessionDescriptorStr, + "_" // + ); + has = IsValidSize(partsCount) && partsCount == 3; + if (has) + { + // + string iName = parts[0]; + string iStart = parts[1]; + string iEnd = parts[2]; + has = IsSpecifiedValid(iName) && + IsSpecifiedValid(iStart) && + IsSpecifiedValid(iEnd); + if (has) + { + // + // Set Active Session Per Symbols ... + XTradeSession session; + + // + session.end = iEnd; + session.name = iName; + session.start = iStart; + + // + AddRef( + session, + sessions // + ); + + // + session.Clean(); + } + } + + // + SpecifiedClean(parts); + } + } + + // + SpecifiedClean(_sessions); + } + + // + // Parse Restrictions ... + void ParseRestrictions(string descriptor) + { + // + // Validate ... + if (!IsSpecifiedValid(descriptor)) + { + return; + } + + // + // Extract Content ... + descriptor = ExtractString(descriptor); + if (!IsSpecifiedValid(descriptor)) + { + return; + } + + // + int count = 0; + bool has = false; + string iRestrictionsParts[]; + + // + // Extract Parts ... + count = SplitContent( + iRestrictionsParts, + descriptor, + "," // + ); + has = IsValidSize(count); + if (!has) + { + // + // Default Restrictions ... + ApplyDefaultRestrictions(); + return; + } + + // + // Try To Extract Required Parts ... + bool hasRestrictionsPeriod = count >= 1; + bool hasRestrictionsPeriodMultiplier = count >= 2; + bool hasMaxAllowedTPs = count >= 3; + bool hasMaxAllowedSLs = count >= 4; + bool hasMaxAllowedTrades = count >= 5; + bool hasCloseAllOpenTradesAt = count >= 6; + + // + // Restrictions Period ... + restrictionsPeriod = + hasRestrictionsPeriod + ? ToXRestrictionPeriod(Trim(iRestrictionsParts[0])) + : XTRADE_RESTRICATION_NONE; + + // + // Restrictions Period Multiplier ... + restrictionsPeriodMultiplier = + hasRestrictionsPeriodMultiplier + ? (int)(Trim(iRestrictionsParts[1])) + : 1; + + // + // Max Allowed TPs ... + maxAllowedTPs = + hasMaxAllowedTPs + ? (int)(Trim(iRestrictionsParts[2])) + : 0; + + // + // Max Allowed SLs ... + maxAllowedSLs = + hasMaxAllowedSLs + ? (int)(Trim(iRestrictionsParts[3])) + : 0; + + // + // Max Allowed Trades ... + maxAllowedTrades = + hasMaxAllowedTrades + ? (int)(Trim(iRestrictionsParts[4])) + : 0; + + // + // Close All Open Trades At ... + closeAllOpenTradesAt = + hasCloseAllOpenTradesAt + ? Trim(iRestrictionsParts[5]) + : NULL; + } + + // + // Apply Default Restrictions ... + void ApplyDefaultRestrictions() + { + // + maxAllowedTPs = 0; + maxAllowedSLs = 0; + maxAllowedTrades = 0; + closeAllOpenTradesAt = NULL; + restrictionsPeriod = XTRADE_RESTRICATION_NONE; + } + + // + // Handle Restrictions ... + void HandleRestrictions(datetime time = NULL) + { + // + // Normalize Time ... + time = NormalizeTime(time); + + // + // Check Restrictions Requirements ... + bool has = HasRestrictions(restrictionsPeriod) && + restrictionsPeriodMultiplier >= 1; + if (!has) + { + return; + } + + // + // Check Restrictions Start ... + has = IsSpecifiedValid(managedStart); + if (!has) + { + managedStart = time; + } + + // + // Calculating Expiration Date based on Config ... + int expiredDelay = restrictionsPeriodMultiplier * GetXRestrictionsPeriodSeconds(restrictionsPeriod); + datetime expiredDate = (datetime)(TimeToSeconds(managedStart) + expiredDelay); + + // + // Check Expiration ... + has = time >= expiredDate; + if (!has) + { + return; + } + + // + ResetRestrictions(); + } + + // + // Reset Restrictions ... + void ResetRestrictions() + { + // + managedSLs = 0; + managedTPs = 0; + managedTrades = 0; + managedBalance = 0; + managedProfits = 0; + managedStart = TimeCurrent(); + } + + // +}; + +// +// an Structure to Describe a Trade ... +struct XTradeInfo +{ + // + // Props ... + double swap; + double profit; + XSignal signal; + ulong positionID; + double commission; + string conditions; + double bullishScore; + double bearishScore; + ENUM_XTRADE_FINALIZATION finalize; + + // + datetime signaledAt; + datetime executedAt; + datetime finalizedAt; + + // + // Constructor ... + XTradeInfo() + { + Clean(); + } + + // + // Tools ... + + /** + * Cleanup Model ... + */ + void Clean() + { + // + swap = 0; + profit = 0; + signal.Clean(); + commission = 0; + positionID = 0; + conditions = NULL; + bullishScore = 0; + bearishScore = 0; + finalize = XTRADE_FINAL_NONE; + + // + signaledAt = NULL; + executedAt = NULL; + finalizedAt = NULL; + + // + ZeroMemory(this); + } + + /** + * Check Has Signal ... + * + * @return ( bool ) + */ + bool HasSignal() + { + // + bool result = false; + + // + result = signal.IsValid(); + + // + return result; + } + + /** + * Check Signal Executed or Not ... + * + * @return ( bool ) + */ + bool IsExecuted() + { + // + bool result = false; + + // + result = positionID > 0; + + // + return result; + } + + /** + * Check a Trade is Finalized or not ... + * + * @return ( bool ) + */ + bool IsFinalized() + { + // + bool result = false; + + // + result = HasSignal() && + IsExecuted() && + finalize != XTRADE_FINAL_NONE; + + // + return result; + } + + /** + * Generate Summary Info ... + * + * @return ( string ) + */ + string Summary() + { + // + string result = NULL; + + // + result = + // + ToXString("Swap", swap) + + ToXString("Profit", profit) + + ToXString("Commission", commission) + + ToXString("Finalize", ToXString(finalize)) + + ToXString("PositionID", positionID) + + ToXString("----------------") + "\n" + + ToXString("Signaled At", ToFormatString(signaledAt)) + + ToXString("Executed At", ToFormatString(executedAt)) + + ToXString("Finalized At", ToFormatString(finalizedAt)) + // + ; + + // + return result; + } + + /** + * Get Data Collection File Name ... + * + * @return ( string ) + */ + string GetFileName() + { + // + string result = NULL; + + // + bool hasSignal = HasSignal(); + bool isExecuted = IsExecuted(); + bool isFinalized = IsFinalized(); + if (!hasSignal && !isExecuted && !isFinalized) + { + return result; + } + + // + result = + // + signal.symbol + "\\" + + ToString(signal.type) + "\\" + + (profit >= 0 ? "Profit" : "Loss") + "\\" + + ToString(positionID) + "_" + + ToString(signal.period) + "_" + + ToFormatString(signaledAt) + // + ; + + // + return result; + } + + /** + * Converts Model to String Representation ... + * + * @param onlySignals: Boolean, Specified Represent Only Signal or not ... + * + * @return ( string ) + */ + string ToString( + bool includeSummary = true, + bool includeSignal = true, + bool includeConditions = true // + ) + { + // + string result = NULL; + + // + // Generating Model Summary ... + string summary = Summary(); + + // + // Generating Signal Summary ... + string signalSummary = signal.ToString(); + + // + if (includeSummary) + { + // + result += + ToXString("----------------") + "\n" + + ToXString("Summary: ") + "\n" + + ToXString("----------------") + "\n" + + summary + "\n"; + } + + // + if (includeSignal) + { + // + result += + ToXString("----------------") + "\n" + + ToXString("Signal: ") + "\n" + + ToXString("----------------") + "\n" + + signalSummary + "\n"; + } + + // + if (includeConditions) + { + // + result += + ToXString("----------------") + "\n" + + ToXString("Conditions: ") + "\n" + + ToXString("----------------") + "\n" + + conditions + "\n"; + } + + // + return result; + } + + string GetConditionsString() + { + // + string result = NULL; + + // + string conditionsStr = + conditions; + string condParts[]; + int condPartsCount = SplitContent( + condParts, + conditionsStr, + "\n" // + ); + if (IsValidSize(condPartsCount)) + { + // + conditionsStr = NULL; + while (HasChild(condParts)) + { + // + string iStr = condParts[0]; + ArrayRemove( + condParts, + 0, + 1 // + ); + + // + bool isLast = !HasChild(condParts); + + // + bool isCond = Contains( + "is", + iStr, + false // + ); + if (isCond) + { + // + string iParts[]; + int iPartsCount = SplitContent( + iParts, + iStr, + ":" // + ); + if (iPartsCount == 2) + { + // + string iVal = iParts[1]; + StringTrimLeft(iVal); + StringTrimRight(iVal); + bool isPassed = ToBoolean(iVal); + conditionsStr += (isPassed ? "" : "!") + "conditions." + iParts[0] + (!isLast ? " &&" : "") + "\n"; + } + } + } + SpecifiedClean(condParts); + } + else + { + conditionsStr = NULL; + } + + // + result = + "(" + "\n" + + "\\" + "\\" + " " + ToXString("Type", ToXString(signal.type)) + + "\\" + "\\" + " " + ToXString("Profit", profit) + + "\\" + "\\" + " " + ToXString("Finalize", ToXString(finalize)) + + "\\" + "\\" + " " + ToXString("PositionID", positionID) + + "\\" + "\\" + " " + ToXString("----------------") + "\n" + + "\\" + "\\" + " " + ToXString("Signaled At", ToFormatString(signaledAt)) + + "\\" + "\\" + " " + ToXString("Executed At", ToFormatString(executedAt)) + + "\\" + "\\" + " " + ToXString("Finalized At", ToFormatString(finalizedAt)) + + "\\" + "\\" + " " + ToXString("----------------") + "\n" + + "\\" + "\\" + " " + ToXString("Scores:") + "\n" + + "\\" + "\\" + " " + ToXString("Bullish", bullishScore) + + "\\" + "\\" + " " + ToXString("Bearish", bearishScore) + + "\\" + "\\" + " " + ToXString("----------------") + "\n" + + conditionsStr + + (IsValid(conditionsStr) ? "" : "") + + ") && "; + + // + return result; + } +}; + +// +// TypeDefs ... + +// +typedef void (*TOnSignal)(XSignal &signal); + +// +typedef bool (*TCanAnalyse)( + string _symbol, + ENUM_TIMEFRAMES _period, + datetime _time // +); + +// +// an Event Type for Notify Guard Triggered ... +typedef void (*TOnGuarded)( + ENUM_X_GUARD_ACTIONS guard, + XPosition &positions[]); + +// +typedef int (*TCheckForGuard)( + XGuard &guards[], + XPosition &positions[], + int barIndex = 0 // +); + +// +typedef void (*TOnDealsChanged)(int count); + +// +typedef void (*TOnOrdersChanged)(int count); + +// +typedef void (*TOnPositionsChanged)(int count); + +// +typedef void (*TOnStopLoss)(const XDeal &deal); +typedef void (*TOnTakeProfit)(const XDeal &deal); + +// +typedef void (*TOnTradeStateChanged)(const XOnTradeHandlerState &state); + +// +typedef void (*TOnForceClose)( + const ulong ticket, + const XPosition &position, + const string comment // +); + +// +typedef void (*TOnPartialClose)( + const ulong ticket, + const double profit, + const string comment // +); + +// +typedef void (*TOnModify)( + const ulong ticket, + const double profit, + const string comment // +); + +// +// Classes ... + +// +// Tools ... + +// +bool IsValid(ENUM_X_ORDER_MODES value) +{ + return value != X_ORDER_MODE_NOTHING; +} + +// +bool IsXBullish(ENUM_POSITION_TYPE type) +{ + return type == POSITION_TYPE_BUY; +} + +// +bool IsXBullish(ENUM_X_POSITION_TYPES type) +{ + return type == X_POSITION_TYPE_LONG; +} + +// +bool IsXBearish(ENUM_POSITION_TYPE type) +{ + return type == POSITION_TYPE_SELL; +} + +// +bool IsXBearish(ENUM_X_POSITION_TYPES type) +{ + return type == X_POSITION_TYPE_SHORT; +} + +// +// Ages ... + +// +// Retrieve a Position Age ... +int GetAge( + XSignal &signal, // Selected Signal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + signal.symbol, + period, + signal.time); + + // + return result; +} +int GetXAge( + XSignal &signal, // Selected Signal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + return GetAge(signal, period); +} + +// +// Retrieve a Position Age ... +int GetAge( + XPosition &position, // Selected Position ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + position.symbol, + period, + position.openAt); + + // + return result; +} +int GetXAge( + XPosition &position, // Selected Position ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + return GetAge(position, period); +} + +// +// Retrieve an Order Age ... +int GetAge( + XOrder &order, // Selected Order ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + order.symbol, + period, + order.setupAt); + + // + return result; +} +int GetXAge( + XOrder &order, // Selected Order ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + return GetAge(order, period); +} + +// +// Retrieve a Deal Age ... +int GetAge( + XDeal &deal, // Selected Deal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + // + int result = -1; + + // + if (period == NULL) + { + period = _Period; + } + + // + result = iBarShift( + deal.symbol, + period, + deal.time); + + // + return result; +} +int GetXAge( + XDeal &deal, // Selected Deal ... + ENUM_TIMEFRAMES period = NULL // Dest Time Frame ... +) +{ + return GetAge(deal, period); +} + +// +// Get Oldest Deal ... +int GetOldest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} +int GetXOldest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + return GetOldest(item, items); +} + +// +// Get Youngest Deal ... +int GetYoungest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XDeal tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XDeal iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} +int GetXYoungest( + XDeal &item, // Hold Result ... + XDeal &items[] // Source Array ... +) +{ + return GetYoungest(item, items); +} + +// +// Get Oldest Order ... +int GetOldest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} +int GetXOldest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + return GetOldest(item, items); +} + +// +// Get Youngest Order ... +int GetYoungest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XOrder tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XOrder iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} +int GetXYoungest( + XOrder &item, // Hold Result ... + XOrder &items[] // Source Array ... +) +{ + return GetYoungest(item, items); +} + +// +// Get Oldes Position ... +int GetOldest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge > 0 && + (tmpAge == 0 || tmpAge < iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge > 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} +int GetXOldest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + return GetOldest(item, items); +} + +// +// Get Youngest Position ... +int GetYoungest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + // + int result = -1; + + // + int itemsCount = ArraySize(items); + if (itemsCount <= 0) + { + return result; + } + + // + int tmpAge = 0; + XPosition tmpItem; + for (int i = 0; i < itemsCount; i++) + { + // + XPosition iItem = items[i]; + + // + int iAge = GetAge(iItem); + if (iAge >= 0 && + (tmpAge == 0 || tmpAge > iAge)) + { + // + tmpAge = iAge; + tmpItem = iItem; + } + } + + // + if (tmpAge >= 0) + { + // + result = tmpAge; + item = tmpItem; + } + + // + return result; +} +int GetXYoungest( + XPosition &item, // Hold Result ... + XPosition &items[] // Source Array ... +) +{ + return GetYoungest(item, items); +} + +// +int FindMaxProfitIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double max = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit <= 0) + { + continue; + } + + // + if (max == 0 || + max < iPosition.profit) + { + // + result = i; + max = iPosition.profit; + } + } + + // + return result; +} + +// +int FindMinProfitIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double min = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit <= 0) + { + continue; + } + + // + if (min == 0 || + min > iPosition.profit) + { + // + result = i; + min = iPosition.profit; + } + } + + // + return result; +} + +// +int ExtractInProfitPositions( + XPosition &positions[], // Position Collection + XPosition &inProfits[] // Result +) +{ + // + int result = 0; + + // + Clean(inProfits); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit > 0) + { + // + AddRef( + iPosition, + inProfits // + ); + } + } + + // + result = ArraySize(inProfits); + + // + return result; +} + +// +int FindMaxDrawdownIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double max = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit >= 0) + { + continue; + } + + // + if (max == 0 || + MathAbs(max) < MathAbs(iPosition.profit)) + { + // + result = i; + max = iPosition.profit; + } + } + + // + return result; +} + +// +int FindMinDrawdownIndex( + XPosition &positions[] // Position Collection +) +{ + // + int result = -1; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + double min = 0; + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + if (iPosition.profit >= 0) + { + continue; + } + + // + if (min == 0 || + min > iPosition.profit) + { + // + result = i; + min = iPosition.profit; + } + } + + // + return result; +} + +// +int ExtractInDrawdownPositions( + XPosition &positions[], // Position Collection + XPosition &inDradowns[] // Result +) +{ + // + int result = 0; + + // + Clean(inDradowns); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.profit < 0) + { + // + AddRef( + iPosition, + inDradowns // + ); + } + } + + // + result = ArraySize(inDradowns); + + // + return result; +} + +// +// Check Filters ... + +// +// Magic Filter ... +template +bool IsMagicFilterPassed( + ulong magic, + bool filterByMagic, + T &item + // +) +{ + // + return !filterByMagic + ? true + : !NotEmpty(magic) + ? false + : magic == item.magic; +} + +// +// Symbol Filter ... +template +bool IsSymbolFilterPassed( + string symbol, + T &item + // +) +{ + // + return !IsValid(symbol) + ? true + : symbol == item.symbol; +} + +// +// Provider Filter ... +template +bool IsProviderFilterPassed( + string provider, + T &item + // +) +{ + // + return !IsValid(provider) + ? true + : provider == item.provider || + Contains(provider, item.provider); +} + +// +// Period Filter ... +template +bool IsPeriodFilterPassed( + ENUM_TIMEFRAMES period, + T &item + // +) +{ + // + return !IsValid(period) + ? true + : period == item.period; +} + +// +// Type Filter ... +template +bool IsTypeFilterPassed( + ENUM_POSITION_TYPE type, + T &item + // +) +{ + // + bool result = type == item.type; + + // + return result; +} +template +bool IsTypeFilterPassed( + ENUM_X_POSITION_TYPES type, + T &item + // +) +{ + // + bool result = type == NULL || type == X_POSITION_TYPE_ALL + ? true + : ((type == X_POSITION_TYPE_LONG && ((int)item.type == (int)POSITION_TYPE_BUY || (int)item.type == (int)ORDER_TYPE_BUY)) || + (type == X_POSITION_TYPE_SHORT && ((int)item.type == (int)POSITION_TYPE_SELL || (int)item.type == (int)ORDER_TYPE_SELL))); + + // + return result; +} +template +bool IsTypeFilterPassed( + ENUM_ORDER_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} +template +bool IsTypeFilterPassed( + ENUM_DEAL_TYPE type, + T &item + // +) +{ + // + return type == NULL + ? true + : type == item.type; +} + +// +// Mode Filter ... +template +bool IsModeFilterPassed( + ENUM_X_ORDER_MODES mode, + T &item + // +) +{ + // + return mode == NULL + ? true + : mode == item.mode; +} + +// +// Entry Filter ... +template +bool IsEntryFilterPassed( + ENUM_DEAL_ENTRY entry, + T &item + // +) +{ + // + return entry == NULL + ? true + : entry == item.entry; +} + +// +// Reason Filter ... +template +bool IsReasonFilterPassed( + ENUM_DEAL_REASON reason, + T &item + // +) +{ + // + return reason == NULL + ? true + : reason == item.reason; +} + +// +// State Filter ... +template +bool IsStateFilterPassed( + ENUM_ORDER_STATE state, + T &item + // +) +{ + // + return state == NULL + ? true + : state == item.state; +} + +// + +// +// +// Calculate Positions Profit Summary ... +double SpecifiedCalculatePositionsProfit( + XPosition &positions[] // Source +) +{ + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + result += iPosition.profit; + } + + // + return result; +} + +// +// Calculate Required Profit for Hedging ... +double SpecifiedCalculateRequiredProfitForHedge( + XPosition &positions[], // Source + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + double result = 0; + + // + int positionsCount = ArraySize(positions); + if (positionsCount <= 0) + { + return result; + } + + // + bool isHedgingEnable = mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0; + if (!isHedgingEnable) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (mMinProfitPerTrade > 0 && mMinProfitPerVolumeFactor > 0) + { + // + result += + ((iPosition.volume / mMinProfitPerVolumeFactor) * + mMinProfitPerTrade) + + (-1 * iPosition.swap); + } + } + + // + return result; +} + +// +bool SpecifiedIsPositionsReadyForHedge( + XPosition &positions[], // Source + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + double profit = SpecifiedCalculatePositionsProfit(positions); + double requiredProfit = SpecifiedCalculateRequiredProfitForHedge( + positions, + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + + // + bool result = requiredProfit > 0 + ? profit >= requiredProfit + : profit > requiredProfit; + + // + return result; +} + +// +int FindCoverageDrawdownPosition( + XPosition &position, // In Drawdown Position + XPosition &inProfits[], // In Profit Positions + XPosition &coverage[], // Coverage Positons + double mMinProfitPerTrade, + double mMinProfitPerVolumeFactor // +) +{ + // + int result = 0; + + // + Clean(coverage); + + // + if (!position.IsValid() || position.profit >= 0) + { + return result; + } + + // + int inProfitsCount = ArraySize(inProfits); + if (!IsValidSize(inProfitsCount)) + { + return result; + } + + // + // Copy in Profits to TMP ... + XPosition tmp[]; + Copy( + inProfits, + tmp // + ); + + // + bool isCoverPassed = false; + while (!isCoverPassed || ArraySize(tmp) > 0) + { + // + XPosition max; + int idx = FindMaxProfitIndex(tmp); + if (idx >= 0) + { + // + if (tmp[idx].profit > 0) + { + AddRef( + tmp[idx], + coverage // + ); + + // + ArrayRemove( + tmp, + idx, + 1 // + ); + } + } + + // + // Check Cover Passed ... + XPosition tmpPositions[]; + Copy( + coverage, + tmpPositions // + ); + AddRef( + position, + tmpPositions // + ); + + // + double profits = SpecifiedCalculatePositionsProfit(tmpPositions); + double requiredProfit = SpecifiedCalculateRequiredProfitForHedge( + tmpPositions, + mMinProfitPerTrade, + mMinProfitPerVolumeFactor // + ); + isCoverPassed = profits >= requiredProfit; + if (isCoverPassed) + { + break; + } + + // + if (!isCoverPassed && ArraySize(tmp) == 0) + { + break; + } + } + + // + result = ArraySize(coverage); + + // + return result; +} + +// +// Extract a Collection of Positions SL ... +int ExtractSLs( + XPosition &positions[], + double &sls[] // +) +{ + // + int result = 0; + + // + Clean(sls); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.sl > 0) + { + // + Add( + iPosition.sl, + sls // + ); + } + } + + // + result = ArraySize(sls); + + // + return result; +} + +// +// Extract a Colletion of Positions TP ... +int ExtractTPs( + XPosition &positions[], + double &tps[] // +) +{ + // + int result = 0; + + // + Clean(tps); + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return result; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + if (iPosition.tp > 0) + { + // + Add( + iPosition.tp, + tps // + ); + } + } + + // + result = ArraySize(tps); + + // + return result; +} + +// +// Retrieve String Representation ... +string ToString(ENUM_X_SIGNAL_EXECUTION_RESULT value) +{ + // + string result = NULL; + + // + switch (value) + { + // + case X_SIGNAL_EXECUTION_UNKNOWN: + result = "Unknown"; + break; + + // + case X_SIGNAL_EXECUTION_SUCCEED: + result = "Succed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_SPREAD: + result = "Spread more than Max Allowed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_NOT_ALLOWED: + result = "not Allowed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_NO_EQUITY: + result = "No Equity for Trade"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_PRICE_ERROR: + result = "Price Error"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_PREV_PROFIT_ERROR: + result = "Previous Position Profit not Passed for Accept Next"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_MAX_REACHED: + result = "Max Allowed Positions Reached"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_DELAY_NOT_PASSED: + result = "Min Delay Between to Signal not Passed"; + break; + + // + case X_SIGNAL_EXECUTION_FAILED_INVALID_PARAMS: + result = "Invalid Params"; + break; + } + + // + return result; +} + +// +// Converts Position Type to Order Type ... +ENUM_ORDER_TYPE ToOrderType(ENUM_POSITION_TYPE value) +{ + // + bool isLong = IsLong(value); + + // + ENUM_ORDER_TYPE result = + isLong + ? ORDER_TYPE_BUY + : ORDER_TYPE_SELL; + + // + return result; +} +ENUM_ORDER_TYPE ToOrderType(ENUM_X_POSITION_TYPES value) +{ + // + ENUM_POSITION_TYPE mType = + value == X_POSITION_TYPE_SHORT + ? POSITION_TYPE_SELL + : POSITION_TYPE_BUY; + + // + bool isLong = IsLong(mType); + + // + ENUM_ORDER_TYPE result = + isLong + ? ORDER_TYPE_BUY + : ORDER_TYPE_SELL; + + // + return result; +} + +// +// Tagging ... + +// +// Generate Specified Tag for Using in Comments ... +string GeneratePeriodTag(ENUM_TIMEFRAMES period) +{ + // + string strPeriod = ToXString(period); + return Surround( + XPeriodToken, + strPeriod + // + ); +} + +// +// Extract Period from a Tagged string ... +ENUM_TIMEFRAMES ExtractPeriod(string value) +{ + // + ENUM_TIMEFRAMES result = NULL; + + // + string pStr = ParseStringSurrounded( + value, + XPeriodToken + // + ); + if (!IsValid(pStr)) + { + return result; + } + + // + result = ToPeriod(pStr); + + // + return result; +} + +// Generate Specified Tag for Using in Comments ... +string GenerateProviderTag(string provider) +{ + // + return Surround( + XProviderToken, + provider + // + ); +} + +// +// Extract Provider from a Tagged string ... +string ExtractProvider(string value) +{ + // + return ParseStringSurrounded( + value, + XProviderToken + // + ); +} + +// +// Generate Support Comment Tag ... +string GenerateSupportTag(ulong ticket) +{ + // + return Surround( + XSupportToken, + ticket + // + ); +} + +// +// Extract Support Positions from a Tagged string ... +ulong ExtractSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XSupportToken + // + ); +} + +// +// Extract Support ... +template +int ExtractSupports( + T &source[], + T &dest[] // Result ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int sourceCount = ArraySize(source); + if (!IsValidSize(sourceCount)) + { + return result; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + ulong isSupport = ExtractSupportedTicket(iSource.comment) > 0; + ulong iEQMSupport = ExtractEQMSupportedTicket(iSource.comment) > 0; + if (isSupport || iEQMSupport) + { + // + AddRef( + iSource, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// Generate EQM Support Comment Tag ... +string GenerateEQMSupportTag(ulong ticket) +{ + // + return Surround( + XEQMSupportToken, + ticket + // + ); +} + +// +// Extract EQM Support Positions from a Tagged string ... +ulong ExtractEQMSupportedTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XEQMSupportToken + // + ); +} + +// +bool IsSupport(string value) +{ + // + bool result = false; + + // + bool isSupport = ExtractSupportedTicket(value) > 0; + bool isEQMSupport = ExtractEQMSupportedTicket(value) > 0; + + // + result = + // + isSupport + // + || + // + isEQMSupport + // + ; + + // + return result; +} + +// +ulong ExtractParentTicket(string value) +{ + // + ulong result = 0; + + // + if (!IsSupport(value)) + { + return result; + } + + // + result = ExtractSupportedTicket(value); + if (result > 0) + { + return result; + } + + // + result = ExtractEQMSupportedTicket(value); + + // + return result; +} + +// +// XRecovery ... + +// +string GenerateRecoveryTag(ulong ticket) +{ + // + return Surround( + XRecoveryToken, + ticket // + ); +} + +// +ulong ExtractRecoveredTicket(string value) +{ + // + return ParseLongSurrounded( + value, + XRecoveryToken // + ); +} + +// +// Extract Recoveries ... +template +int ExtractRecoveries( + T &source[], + T &dest[] // Result ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int sourceCount = ArraySize(source); + if (!IsValidSize(sourceCount)) + { + return result; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + T iSource = source[i]; + + // + ulong isRecovery = ExtractRecoveredTicket(iSource.comment) > 0; + if (isRecovery) + { + // + AddRef( + iSource, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// Extract Specified Position's Recoveries ... +int ExtractRecoveries( + ulong ticket, + XPosition &source[], + XPosition &dest[] // Result ... +) +{ + // + int result = 0; + + // + Clean(dest); + + // + int sourceCount = ArraySize(source); + if (!IsValidSize(sourceCount)) + { + return result; + } + + // + for (int i = 0; i < sourceCount; i++) + { + // + XPosition iSource = source[i]; + + // + ulong parentTicket = ExtractRecoveredTicket(iSource.comment); + bool isRecovery = parentTicket > 0; + if (isRecovery && parentTicket == ticket) + { + // + AddRef( + iSource, + dest // + ); + } + } + + // + result = ArraySize(dest); + + // + return result; +} + +// +// SL Trails ... + +// +// Extract SL Trail Level ... +int ExtractSLTrailLevel(string comment) +{ + // + int result = 0; + + // + if (!IsValid(comment)) + { + return result; + } + + // + result = ParseIntSurrounded( + comment, + XSLTrailToken + // + ); + + // + return result; +} + +// +// Generate SL Trail Comment Tag ... +string GenerateSLTrailTag(int level) +{ + // + string result = NULL; + + // + if (level <= 0) + { + return result; + } + + // + result = Surround( + XSLTrailToken, + level + // + ); + + // + return result; +} + +// +// Prepare SL Trail Comment ... +string PrepareSLTrailTag( + const string comment // Original Position Comment ... +) +{ + // + string result = NULL; + + // + int level = 0; + result = comment; + + // + // Check Comment Contains SL Trailing or not ... + int lastTrailLevel = ExtractSLTrailLevel(comment); + if (lastTrailLevel <= 0) + { + level++; + } + else + { + // + level = lastTrailLevel + 1; + string lastLevelStr = GenerateSLTrailTag(lastTrailLevel); + StringReplace( + result, + lastLevelStr, + "" + // + ); + } + + // + // Generate level Comment ... + string levelStr = GenerateSLTrailTag(level); + result += levelStr; + + // + return result; +} + +// +// Count Positions from a Collection ... +void CountPositions( + const XPosition &positions[], + int &longs, + double &longProfits, + double &longVolumes, // + // + int &shorts, + double &shortProfits, + double &shortVolumes // +) +{ + // + longs = 0; + longProfits = 0; + longVolumes = 0; + + // + shorts = 0; + shortProfits = 0; + shortVolumes = 0; + + // + int positionsCount = ArraySize(positions); + if (!IsValidSize(positionsCount)) + { + return; + } + + // + for (int i = 0; i < positionsCount; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isLong = IsLong(iPosition.type); + if (isLong) + { + // + longs++; + longProfits += iPosition.profit; + longVolumes += iPosition.volume; + } + else + { + // + shorts++; + shortProfits += iPosition.profit; + shortVolumes += iPosition.volume; + } + } +} + +// +// Extract Positions based On Type ... +void ExtractPositions( + XPosition &positions[], + XPosition &longs[], + XPosition &shorts[] // +) +{ + // + int count = ArraySize(positions); + if (!IsValidSize(count)) + { + return; + } + + // + Clean(longs); + Clean(shorts); + + // + for (int i = 0; i < count; i++) + { + // + XPosition iPosition = positions[i]; + + // + bool isLong = IsLong(iPosition.type); + if (isLong) + { + AddRef( + iPosition, + longs // + ); + } + else + { + AddRef( + iPosition, + shorts // + ); + } + } +} + +// +// Apply a Collection of Targets +// on Specified Signal ... +void ApplyTargetsOnSignal( + ENUM_X_DIRECTION sortingDir, // Target Sorting Direction ... + XTarget &targets[], // Required Targets ... + XSignal &signal // Destination Signal ... +) +{ + // + bool has = + HasChild(targets) && + HasDirection(sortingDir); + if (!has) + { + return; + } + + // + // Sort Targets ... + ApplySortOnTargets( + sortingDir, + targets // + ); + + // + // Compare TP with Targets ... + int idx = IsLong(signal.type) + ? GetHighest(targets) + : GetLowest(targets); + has = IsValidIndex(idx); + if (has) + { + // + // Compare TP ... + has = IsLong(signal.type) + ? targets[idx].target > signal.tp + : targets[idx].target < signal.tp; + if (has) + { + // + XTarget tpTarget; + tpTarget = targets[idx]; + tpTarget.actingDistance = 0; + tpTarget.target = signal.tp; + + // + signal.tp = targets[idx].target; + targets[idx].actingDistance = 0; + + // + ArrayRemove( + targets, + idx, + 1 // + ); + + // + AddRef( + tpTarget, + targets // + ); + } + + // + // Sort Targets ... + ApplySortOnTargets( + sortingDir, + targets // + ); + } + + // + Copy( + targets, + signal.targets // + ); +} + +/** + * Select Specified Position's Related Position(s) + * for Protecting ... + * + * @param selecteds: XPosition instance reference Collection, for Holding Selected Positions ... + * @param positions: XPosition instance reference Collection, All available source Positions ... + * @param forType: ENUM_X_POSITION_TYPES member, Spcified Position Type to Select for it ... + * @param selectType: ENUM_XPOSITION_SELECT_TYPES member, Specified Positions Selecting Senario ... + * + * @return ( bool ) + */ +bool SelectPosition( + XPosition &selecteds[], + XPosition &positions[], + ENUM_X_POSITION_TYPES forType, + ENUM_XPOSITION_SELECT_TYPES selectType // +) +{ + // + bool result = false; + + // + // Normalize Args ... + Clean(selecteds); + + // + // Validate Args ... + result = + IsValid(forType) && + HasChild(positions) && + IsXValid(selectType); + if (!result) + { + return result; + } + + // + // Extract Separate Type of Positions ... + + // + int idx = -1; + bool has = false; + XPosition iPosition; + + // + bool isLong = IsLong(forType); + bool isShort = IsShort(forType); + int count = ArraySize(positions); + + // + XPosition samePositions[]; + XPosition oppositPositions[]; + XPosition inProfitPositions[]; + XPosition inDrawdownPositions[]; + XPosition sameInProfitPositions[]; + XPosition sameInDrawdownPositions[]; + XPosition oppositInProfitPositions[]; + XPosition oppositInDrawdownPositions[]; + + // + for (int i = 0; i < count; i++) + { + // + // Select Indexed Position ... + iPosition = positions[i]; + + // + bool isIPosLong = IsLong(iPosition.type); + bool isIPosShort = IsShort(iPosition.type); + + // + // Select if Same Type ... + bool isSame = + (isLong && isIPosLong) || + (isShort && isIPosShort); + if (isSame) + { + // + AddRef( + iPosition, + samePositions // + ); + } + + // + // Select if Opposit Type ... + bool isOpposit = + (isLong && isIPosShort) || + (isShort && isIPosLong); + if (isOpposit) + { + // + AddRef( + iPosition, + oppositPositions // + ); + } + + // + iPosition.Clean(); + } + + // + // Filling Other Requirement Collections ... + + // + ExtractInProfitPositions( + positions, + inProfitPositions // + ); + + // + ExtractInProfitPositions( + samePositions, + sameInProfitPositions // + ); + + // + ExtractInProfitPositions( + oppositPositions, + oppositInProfitPositions // + ); + + // + ExtractInDrawdownPositions( + positions, + inDrawdownPositions // + ); + + // + ExtractInDrawdownPositions( + samePositions, + sameInDrawdownPositions // + ); + + // + ExtractInDrawdownPositions( + oppositPositions, + oppositInDrawdownPositions // + ); + + // + // Implement Selection Senario ... + switch (selectType) + { + // + case XPOSITION_SELECT_ALL: + // + Copy( + positions, + selecteds // + ); + break; + + // + case XPOSITION_SELECT_IN_PROFITS: + // + Copy( + inProfitPositions, + selecteds // + ); + break; + + // + case XPOSITION_SELECT_IN_DRAWDOWNS: + // + Copy( + inDrawdownPositions, + selecteds // + ); + break; + + // + case XPOSITION_SELECT_OLDEST: + // + GetOldest( + iPosition, + positions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_YOUNGEST: + // + GetYoungest( + iPosition, + positions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_IN_PROFITS_OLDEST: + // + GetOldest( + iPosition, + inProfitPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_IN_PROFITS_YOUNGEST: + // + GetYoungest( + iPosition, + inProfitPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_IN_PROFITS_MIN: + // + idx = FindMinProfitIndex(inProfitPositions); + if (IsValidIndex(idx)) + { + // + iPosition = inProfitPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_IN_PROFITS_MAX: + // + idx = FindMaxProfitIndex(inProfitPositions); + if (IsValidIndex(idx)) + { + // + iPosition = inProfitPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_IN_DRAWDOWN_OLDEST: + // + GetOldest( + iPosition, + inDrawdownPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_IN_DRAWDOWN_YOUNGEST: + // + GetYoungest( + iPosition, + inDrawdownPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_IN_DRAWDOWN_MIN: + // + idx = FindMinDrawdownIndex(inDrawdownPositions); + if (IsValidIndex(idx)) + { + // + iPosition = inDrawdownPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_IN_DRAWDOWN_MAX: + // + idx = FindMaxDrawdownIndex(inDrawdownPositions); + if (IsValidIndex(idx)) + { + // + iPosition = inDrawdownPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAMES: + // + Copy( + samePositions, + selecteds // + ); + break; + + // + case XPOSITION_SELECT_SAMES_OLDEST: + // + GetOldest( + iPosition, + samePositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAMES_YOUNGEST: + // + GetYoungest( + iPosition, + samePositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSITS: + // + Copy( + oppositPositions, + selecteds // + ); + break; + + // + case XPOSITION_SELECT_OPPOSIT_OLDEST: + // + GetOldest( + iPosition, + oppositPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSIT_YOUNGEST: + // + GetYoungest( + iPosition, + oppositPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAME_IN_PROFITS: + // + Copy( + sameInProfitPositions, + selecteds // + ); + break; + + // + case XPOSITION_SELECT_SAME_IN_PROFITS_OLDEST: + // + GetOldest( + iPosition, + sameInProfitPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAME_IN_PROFITS_YOUNGEST: + // + GetYoungest( + iPosition, + sameInProfitPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAME_IN_PROFITS_MIN: + // + idx = FindMinProfitIndex(sameInProfitPositions); + if (IsValidIndex(idx)) + { + // + iPosition = sameInProfitPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAME_IN_PROFITS_MAX: + // + idx = FindMaxProfitIndex(sameInProfitPositions); + if (IsValidIndex(idx)) + { + // + iPosition = sameInProfitPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSIT_IN_PROFITS: + // + Copy( + oppositInProfitPositions, + selecteds // + ); + break; + + // + case XPOSITION_SELECT_OPPOSIT_IN_PROFITS_OLDEST: + // + GetOldest( + iPosition, + oppositInProfitPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSIT_IN_PROFITS_YOUNGEST: + // + GetYoungest( + iPosition, + oppositInProfitPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSIT_IN_PROFITS_MIN: + // + idx = FindMinProfitIndex(oppositInProfitPositions); + if (IsValidIndex(idx)) + { + // + iPosition = oppositInProfitPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSIT_IN_PROFITS_MAX: + // + idx = FindMaxProfitIndex(oppositInProfitPositions); + if (IsValidIndex(idx)) + { + // + iPosition = oppositInProfitPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAME_IN_DRAWDOWNS: + // + Copy( + sameInDrawdownPositions, + selecteds // + ); + break; + + // + case XPOSITION_SELECT_SAME_IN_DRAWDOWN_OLDEST: + // + GetOldest( + iPosition, + sameInDrawdownPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAME_IN_DRAWDOWN_YOUNGEST: + // + GetYoungest( + iPosition, + sameInDrawdownPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAME_IN_DRAWDOWN_MIN: + // + idx = FindMinDrawdownIndex(sameInDrawdownPositions); + if (IsValidIndex(idx)) + { + // + iPosition = sameInDrawdownPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_SAME_IN_DRAWDOWN_MAX: + // + idx = FindMaxDrawdownIndex(sameInDrawdownPositions); + if (IsValidIndex(idx)) + { + // + iPosition = sameInDrawdownPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWNS: + // + Copy( + oppositInDrawdownPositions, + selecteds // + ); + break; + + // + case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_OLDEST: + // + GetOldest( + iPosition, + oppositInDrawdownPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_YOUNGEST: + // + GetYoungest( + iPosition, + oppositInDrawdownPositions // + ); + if (iPosition.IsValid()) + { + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MIN: + // + idx = FindMinDrawdownIndex(oppositInDrawdownPositions); + if (IsValidIndex(idx)) + { + // + iPosition = oppositInDrawdownPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + case XPOSITION_SELECT_OPPOSITS_IN_DRAWDOWN_MAX: + // + idx = FindMaxDrawdownIndex(oppositInDrawdownPositions); + if (IsValidIndex(idx)) + { + // + iPosition = oppositInDrawdownPositions[idx]; + + // + AddRef( + iPosition, + selecteds // + ); + } + iPosition.Clean(); + break; + + // + } + + // + // Validate Result ... + result = HasChild(selecteds); + + // + // Cleanup Resources ... + + // + if (!result) + { + Clean(selecteds); + } + + // + Clean(samePositions); + Clean(oppositPositions); + Clean(inProfitPositions); + Clean(inDrawdownPositions); + Clean(sameInProfitPositions); + Clean(sameInDrawdownPositions); + Clean(oppositInProfitPositions); + Clean(oppositInDrawdownPositions); + + // + return result; +} + +//