Compare commits

...
4 Commits
Author SHA1 Message Date
saherelm 0edd3c1b71 last ... 2026-08-14 19:17:02 +03:30
saherelm 4707856302 last ... 2026-08-14 07:49:18 +03:30
saherelm 9d23e2cba1 Last Works on XSDT Pivot Detector ... 2026-08-14 03:30:03 +03:30
saherelm d50eef35bc add and Test Context Generator ... 2026-08-13 00:36:57 +03:30
8 changed files with 83399 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+557
View File
@@ -0,0 +1,557 @@
#!/usr/bin/env node
/**
* Context Generator Module ...
* a module for Generating Context ...
*
* Maintainer
*
* Hadi Khazaee Asl <https://saherelm.ir> (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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,672 @@
///////////////////////////////////////////////////////
//
// SaherElm IT Center MQL5 Expert Advisor
// -------------------------------------------------
// Name: XBaseEA
// Description: Session Detector Test Expert Advisor ...
//
// 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 Session Detector Test Expert Advisor"
#property strict
// #region Imports ...
#include "../Classes/x-saherelm.pivot-detector.class.mq5"
#include "../Classes/x-saherelm.session-detector.class.mq5"
#include "../Classes/x-saherelm.x-poi.drawer.class.mq5"
// #endregion
// #region Global Variables ...
#define ShortName "XPivotDetectorTestEA"
//
XCAlert *eaAlert;
XCPOIDrawer *eaDrawer;
XCSessionDetector *eaSessionDetector;
//
XCPivotDetector *eaMajorPivotDetector;
XCPivotDetector *eaMinorPivotDetector;
//
// Last Processing Pivots Time ...
bool eaDrawMajorPivots = true;
bool eaDrawMinorPivots = true;
XPOIDrawConfig eaMajorPivotsDrawConfig;
XPOIDrawConfig eaMinorPivotsDrawConfig;
datetime eaLastMajorPivotProcessing = NULL;
datetime eaLastMinorPivotProcessing = NULL;
XPOIDrawConfig eaPointedMajorPivotsDrawConfig;
XPOIDrawConfig eaPointedMinorPivotsDrawConfig;
ENUM_X_DIRECTION eaMajorBias = X_DIRECTION_NONE;
ENUM_X_DIRECTION eaMinorBias = X_DIRECTION_NONE;
// #endregion
// #region Global Event Handlers ...
/**
* Initialize EA Process ...
*
* @return ( int )
*/
int OnInit()
{
//
bool result = true;
//
result = InitializeRequirements();
if (!result)
{
return INIT_FAILED;
}
//
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 ...
//
eaMajorPivotsDrawConfig.Clean();
eaMinorPivotsDrawConfig.Clean();
eaPointedMajorPivotsDrawConfig.Clean();
eaPointedMinorPivotsDrawConfig.Clean();
//
// Cleanup Resources ...
ZeroMemory(eaAlert);
ZeroMemory(eaDrawer);
ZeroMemory(eaSessionDetector);
ZeroMemory(eaMajorPivotDetector);
ZeroMemory(eaMinorPivotDetector);
}
/**
* Handle Tick for Processing ...
*/
void OnTick()
{
//
// Perform Session Detector Process ...
eaSessionDetector.Process();
//
// Process Pivot Detector ...
HandleProcessMajorPviots();
HandleProcessMinorPviots();
//
// Detecting Bias ...
HanldeBiasDetection();
}
/**
* 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 //
)
{
}
// #endregion
// #region Custom Actions ...
/**
* Initial Requirements of EA ...
*
* @return ( bool )
*/
bool InitializeRequirements()
{
//
bool result = false;
//
eaDrawer = new XCPOIDrawer();
//
// Initialize Alert ...
eaAlert = new XCAlert(
ShortName,
false, // Enable Alert ...
false, // Log Alert ...
false, // Terminal Alert ...
false, // Mail Alert ...
false, // Push Alerts ...
false // Save Alerts ...
);
result = eaAlert != NULL;
if (!result)
{
return result;
}
//
// Initialize Session Detector ...
eaSessionDetector = new XCSessionDetector(
eaAlert, // Alert ...
true, // Use Server Time ...
0 // Timezone Offset ...
);
//
// Register Event Handlers ...
eaSessionDetector.AddOnSessionEndHandler(OnSessionEndHandler);
eaSessionDetector.AddOnOverlapEndHandler(OnOverlapEndHandler);
eaSessionDetector.AddOnSessionStartHandler(OnSessionStartHandler);
eaSessionDetector.AddOnOverlapStartHandler(OnOverlapStartHandler);
eaSessionDetector.AddOnSessionStateChangeHandler(OnSessionStateChangeHandler);
//
result = eaSessionDetector != NULL;
if (!result)
{
return result;
}
//
// Initialize Major Pivot Detector ...
eaMajorPivotDetector = new XCPivotDetector(
eaAlert, // Alert ...
"X121SDTMajor", // Pivot Prefix ...
false, // Support Inverted Zones ...
0 // Processable Zones ...
);
//
// Register Event Handlers ...
eaMajorPivotDetector.AddOnPeakBreakedHandler(OnMajorPeakBreakedHandler);
eaMajorPivotDetector.AddOnValeBreakedHandler(OnMajorValeBreakedHandler);
eaMajorPivotDetector.AddOnPeakDetectedHandler(OnMajorPeakDetectedHandler);
eaMajorPivotDetector.AddOnValeDetectedHandler(OnMajorValeDetectedHandler);
//
// Pivot Draw Config ...
eaMajorPivotsDrawConfig.zonesWidth = 2;
eaMajorPivotsDrawConfig.zonesFill = false;
eaMajorPivotsDrawConfig.ignoreZonesAt = true;
eaMajorPivotsDrawConfig.zonesStyle = STYLE_SOLID;
eaMajorPivotsDrawConfig.bullishColor = clrAqua;
eaMajorPivotsDrawConfig.bearishColor = clrMagenta;
//
// Pointed Pivot Draw Config ...
eaPointedMajorPivotsDrawConfig.zonesWidth = 2;
eaPointedMajorPivotsDrawConfig.zonesFill = false;
eaPointedMajorPivotsDrawConfig.ignoreZonesAt = true;
eaPointedMajorPivotsDrawConfig.zonesStyle = STYLE_SOLID;
eaPointedMajorPivotsDrawConfig.bullishColor = clrYellow;
eaPointedMajorPivotsDrawConfig.bearishColor = clrOrange;
//
result = eaMajorPivotDetector != NULL;
if (!result)
{
return result;
}
//
// Initialize Minor Pivot Detector ...
eaMinorPivotDetector = new XCPivotDetector(
eaAlert, // Alert ...
"X121SDTMinor", // Pivot Prefix ...
false, // Support Inverted Zones ...
0 // Processable Zones ...
);
//
// Register Event Handlers ...
eaMinorPivotDetector.AddOnPeakBreakedHandler(OnMinorPeakBreakedHandler);
eaMinorPivotDetector.AddOnValeBreakedHandler(OnMinorValeBreakedHandler);
eaMinorPivotDetector.AddOnPeakDetectedHandler(OnMinorPeakDetectedHandler);
eaMinorPivotDetector.AddOnValeDetectedHandler(OnMinorValeDetectedHandler);
//
// Pivot Draw Config ...
eaMinorPivotsDrawConfig.zonesWidth = 1;
eaMinorPivotsDrawConfig.zonesFill = false;
eaMinorPivotsDrawConfig.ignoreZonesAt = true;
eaMinorPivotsDrawConfig.bearishColor = clrRed;
eaMinorPivotsDrawConfig.bullishColor = clrLime;
eaMinorPivotsDrawConfig.zonesStyle = STYLE_DASHDOT;
//
// Pointed Pivot Draw Config ...
eaPointedMinorPivotsDrawConfig.zonesWidth = 2;
eaPointedMinorPivotsDrawConfig.zonesFill = false;
eaPointedMinorPivotsDrawConfig.ignoreZonesAt = true;
eaPointedMinorPivotsDrawConfig.bearishColor = clrOrange;
eaPointedMinorPivotsDrawConfig.bullishColor = clrYellow;
eaPointedMinorPivotsDrawConfig.zonesStyle = STYLE_DASHDOT;
//
result = eaMinorPivotDetector != NULL;
if (!result)
{
return result;
}
//
return result;
}
/**
* Process Pivots ...
*/
void HandleProcessMajorPviots()
{
//
// Initialize Pivot Processing Bar ...
XOHCL bar;
bool has = bar.Init(
_Symbol,
PERIOD_H4,
1 // Last Completed Bar ...
);
if (!has)
{
return;
}
//
// Validate Passing Bar ...
has =
!IsXValid(eaLastMajorPivotProcessing) ||
bar.time > eaLastMajorPivotProcessing;
if (!has)
{
return;
}
//
eaLastMajorPivotProcessing = bar.time;
//
eaMajorPivotDetector.Process(
bar, // XOHCL Bar ...
2, // Pivot Approvation Length ...
20 // Loopback ...
);
//
// Handle Draw Pivots ...
if (!eaDrawMajorPivots)
{
return;
}
//
XBoxZone tmps[];
FillNotExists(
tmps, // Dest ...
eaMajorPivotDetector.peaks, // Source ...
false // Force Clean ...
);
FillNotExists(
tmps, // Dest ...
eaMajorPivotDetector.vales, // Source ...
false // Force Clean ...
);
if (HasChild(tmps))
{
eaDrawer.DrawZones(
tmps, // Boxes ...
eaMajorPivotsDrawConfig // Draw Config ...
);
}
XClean(tmps);
}
/**
* Process Pivots ...
*/
void HandleProcessMinorPviots()
{
//
// Initialize Pivot Processing Bar ...
XOHCL bar;
bool has = bar.Init(
_Symbol,
PERIOD_M15,
1 // Last Completed Bar ...
);
if (!has)
{
return;
}
//
// Validate Passing Bar ...
has =
!IsXValid(eaLastMinorPivotProcessing) ||
bar.time > eaLastMinorPivotProcessing;
if (!has)
{
return;
}
//
eaLastMinorPivotProcessing = bar.time;
//
eaMinorPivotDetector.Process(
bar, // XOHCL Bar ...
5, // Pivot Approvation Length ...
40 // Loopback ...
);
//
// Handle Draw Pivots ...
if (!eaDrawMinorPivots)
{
return;
}
//
XBoxZone tmps[];
FillNotExists(
tmps, // Dest ...
eaMinorPivotDetector.peaks, // Source ...
false // Force Clean ...
);
FillNotExists(
tmps, // Dest ...
eaMinorPivotDetector.vales, // Source ...
false // Force Clean ...
);
if (HasChild(tmps))
{
eaDrawer.DrawZones(
tmps, // Boxes ...
eaMinorPivotsDrawConfig // Draw Config ...
);
}
XClean(tmps);
}
/**
* Detect Bias based on Pivots ...
*/
void HanldeBiasDetection()
{
//
bool has = false;
//
// Major Bias ...
has =
eaMajorPivotDetector.HasPeaks() &&
eaMajorPivotDetector.HasVales();
if (has)
{
//
int youngestPeakIDX = eaMajorPivotDetector.GetYoungestPeak();
int youngestValeIDX = eaMajorPivotDetector.GetYoungestVale();
has =
IsValidIndex(youngestPeakIDX) &&
IsValidIndex(youngestValeIDX);
if (has)
{
//
eaMajorBias =
eaMajorPivotDetector.peaks[youngestPeakIDX].from > eaMajorPivotDetector.vales[youngestValeIDX].from
? X_DIRECTION_BEARISH
: eaMajorPivotDetector.vales[youngestValeIDX].from > eaMajorPivotDetector.peaks[youngestPeakIDX].from
? X_DIRECTION_BULLISH
: X_DIRECTION_NONE;
}
}
}
// #endregion
// #region Custom Event Handlers ...
// #region Pivot Detector Event Handlers ...
/**
* Calls when a Peak Breaked ...
*
* @param box: XBoxZone instance ...
*/
void OnMajorPeakBreakedHandler(XBoxZone &box)
{
// DebugBreak();
}
/**
* Calls when a Vale Breaked ...
*
* @param box: XBoxZone instance ...
*/
void OnMajorValeBreakedHandler(XBoxZone &box)
{
// DebugBreak();
}
/**
* Calls when a New Peak Detected ...
*
* @param box: XBoxZone instance ...
*/
void OnMajorPeakDetectedHandler(XBoxZone &box)
{
//
eaDrawer.DrawZone(
box, //
eaPointedMajorPivotsDrawConfig //
);
//
DebugBreak();
}
/**
* Calls when a New Vale Detected ...
*
* @param box: XBoxZone instance ...
*/
void OnMajorValeDetectedHandler(XBoxZone &box)
{
//
eaDrawer.DrawZone(
box, //
eaPointedMajorPivotsDrawConfig //
);
//
DebugBreak();
}
/**
* Calls when a Peak Breaked ...
*
* @param box: XBoxZone instance ...
*/
void OnMinorPeakBreakedHandler(XBoxZone &box)
{
// DebugBreak();
}
/**
* Calls when a Vale Breaked ...
*
* @param box: XBoxZone instance ...
*/
void OnMinorValeBreakedHandler(XBoxZone &box)
{
// DebugBreak();
}
/**
* Calls when a New Peak Detected ...
*
* @param box: XBoxZone instance ...
*/
void OnMinorPeakDetectedHandler(XBoxZone &box)
{
//
eaDrawer.DrawZone(
box, //
eaPointedMinorPivotsDrawConfig //
);
//
DebugBreak();
}
/**
* Calls when a New Vale Detected ...
*
* @param box: XBoxZone instance ...
*/
void OnMinorValeDetectedHandler(XBoxZone &box)
{
//
eaDrawer.DrawZone(
box, //
eaPointedMinorPivotsDrawConfig //
);
//
DebugBreak();
}
// #endregion
// #region Session Detector Event Handlers ...
/**
* Handle Session Start Event ...
*
* @param session: ENUM_X_SESSION_TYPE
* @param startTime: datetime
*/
void OnSessionStartHandler(
ENUM_X_SESSION_TYPE session,
datetime startTime //
)
{
// Print("Session Started: ", EnumToString(session), " at ", TimeToString(startTime));
// //
// // Custom Testing ...
// if (session == X_SESSION_NEWYORK)
// {
// DebugBreak();
// }
}
/**
* Handle Session End Event ...
*
* @param session: ENUM_X_SESSION_TYPE
* @param startTime: datetime
*/
void OnSessionEndHandler(
ENUM_X_SESSION_TYPE session,
datetime startTime //
)
{
// Print("Session Ended: ", EnumToString(session), " at ", TimeToString(startTime));
// //
// // Custom Testing ...
// if (session == X_SESSION_NEWYORK)
// {
// DebugBreak();
// }
}
/**
* Handle Overlap Start Event ...
*
* @param session: ENUM_X_SESSION_OVERLAP_TYPE
* @param startTime: datetime
*/
void OnOverlapStartHandler(
ENUM_X_SESSION_OVERLAP_TYPE overlap,
datetime startTime //
)
{
// Print("Overlap Started: ", EnumToString(overlap), " at ", TimeToString(startTime));
// //
// // Custom Testing ...
// if (overlap == X_OVERLAP_LONDON_NEWYORK)
// {
// DebugBreak();
// }
}
/**
* Handle Overlap End Event ...
*
* @param session: ENUM_X_SESSION_OVERLAP_TYPE
* @param startTime: datetime
*/
void OnOverlapEndHandler(
ENUM_X_SESSION_OVERLAP_TYPE overlap,
datetime startTime //
)
{
// Print("Overlap Ended: ", EnumToString(overlap), " at ", TimeToString(startTime));
// //
// // Custom Testing ...
// if (overlap == X_OVERLAP_LONDON_NEWYORK)
// {
// DebugBreak();
// }
}
/**
* Handle Session State Change Event ...
*
* @param session: ENUM_X_SESSION_TYPE
* @param state: ENUM_X_SESSION_STATE
*/
void OnSessionStateChangeHandler(
ENUM_X_SESSION_TYPE session,
ENUM_X_SESSION_STATE state //
)
{
// Print("Session State Changed: ", EnumToString(session), " State: ", EnumToString(state));
}
// #endregion
// #endregion
@@ -3482,6 +3482,74 @@ int FillNotExists(
// //
return result; return result;
} }
template <typename T>
int FillNotExists(
T &dest[],
T &source[],
bool forceClean = false,
ENUM_X_DIRECTION forDir = X_DIRECTION_NONE,
int maxAllowed = 0 //
)
{
//
int result = 0;
//
// Prepare ...
if (forceClean)
{
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;
}
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+
@@ -3654,6 +3722,125 @@ bool IsBoxValid(
return result; return result;
} }
/**
* Validate a Box based on Price ...
*
* @param box: XBoxZone instance, box to Validate ...
* @param barIndex: int, Start Validating Bar's Index ...
* @param pType: ENUM_X_BOUNDARY_PRICE, Price Type for Validation ...
*
* @return ( bool )
*/
bool IsBoxValid(
XBoxZone &box,
int barIndex = 0,
ENUM_X_BOUNDARY_PRICE pType = X_BOUNDARY_PRICE_UP_DOWN //
)
{
//
bool result = false;
//
// Normalize Bar Index ...
barIndex = NormalizeInt(barIndex, 0);
//
// Validaet ...
result =
box.IsValid() &&
IsXValid(pType);
if (!result)
{
return result;
}
//
bool isBullish = box.IsBullish();
//
int fromIDX = box.FromIndex();
result =
IsValidIndex(fromIDX) &&
barIndex < fromIDX;
if (!result)
{
return result;
}
//
// Loop through ...
XOHCL iBar;
bool has = false;
double appliedPrice = EMPTY_VALUE;
for (int i = barIndex; i < fromIDX; i++)
{
//
// Initialize Bar ...
iBar.Clean();
has = iBar.Init(box.symbol, box.period, i);
if (!has)
{
//
result = false;
break;
}
//
// Calculate Applied Price ...
switch (pType)
{
//
case X_BOUNDARY_PRICE_UP_DOWN:
//
appliedPrice =
isBullish
? iBar.GetDown()
: iBar.GetUp();
break;
//
case X_BOUNDARY_PRICE_HIGH_LOW:
//
appliedPrice =
isBullish
? iBar.low
: iBar.high;
break;
//
default:
appliedPrice = EMPTY_VALUE;
break;
}
has = NotEmptyZero(appliedPrice);
if (!has)
{
//
result = false;
break;
}
//
has =
has &&
result &&
(isBullish
? appliedPrice >= box.lower
: appliedPrice <= box.upper);
if (!has) {
//
result = false;
break;
}
//
iBar.Clean();
}
//
return result;
}
// //
void SortBoxes( void SortBoxes(
XBoxZone &items[], XBoxZone &items[],
+298
View File
@@ -0,0 +1,298 @@
#!/usr/bin/env node
/**
* Context Generator Module ...
* a module for Generating Context ...
*
* Maintainer
*
* Hadi Khazaee Asl <https://saherelm.ir> (hadi_khazaee_asl@yahoo.com)
*/
//
//#region Imports ...
const fs = require("fs");
const path = require("path");
//#endregion
//
//#region Constants ...
const outputFilePrefix = "x121XSDT";
const allowedPatterns = [
//
// Base Pilot Files ...
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.pivot-detector.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-pivot-detector.test.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