From e97b44b9380196f95d044fdd7631ae9a10bf723a Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Thu, 9 Oct 2025 12:34:26 +0330 Subject: [PATCH] last works ... --- .../x-saherelm.x-backtester.expert.class.mq5 | 52 +++- Experts/x-saherelm.xfima.backtester.ea.mq5 | 21 ++ Libraries/x-saherelm.x-ohcl.lib.mq5 | 33 +++ Libraries/x-saherelm.x-pivot.analysis.lib.mq5 | 2 +- Libraries/x-saherelm.x-poi.extensions.lib.mq5 | 80 ++++++ .../x-saherelm.xfima.signaller.class.mq5 | 264 ++++++++++++++++-- XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 | 223 ++++++++++++++- 7 files changed, 642 insertions(+), 33 deletions(-) diff --git a/Classes/x-saherelm.x-backtester.expert.class.mq5 b/Classes/x-saherelm.x-backtester.expert.class.mq5 index f9e1d24e..9fecf496 100644 --- a/Classes/x-saherelm.x-backtester.expert.class.mq5 +++ b/Classes/x-saherelm.x-backtester.expert.class.mq5 @@ -66,6 +66,16 @@ class XCBackTesterEA : public XCBase 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 @@ -86,11 +96,10 @@ class XCBackTesterEA : public XCBase XCAlert *eaAlert; // EA Scope Alert 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 ... - // - XCChartHelper *eaChartHelper; // Chart Helper Class ... - // // Constructor ... XCBackTesterEA() @@ -140,6 +149,10 @@ class XCBackTesterEA : public XCBase int count = 0; bool has = false; + // + // Chart Helper ... + eaChartHelper = new XCChartHelper(); + // // Initialize Alert Handler ... eaAlert = new XCAlert(); @@ -297,6 +310,22 @@ class XCBackTesterEA : public XCBase // Init Target Managers ... eaTarget = new XCTarget(eaTrader, eaAlert); + // + eaVolume = new XCVolume(); + result = eaVolume.Init( + eaVolumeSelect, + eaStaticVoluem, + eaDynamicVolumeStepBalance, + eaDynamicVolumeStepVolume, + eaConstantRiskBalance, + eaConstantPercent, + eaConstantBalance // + ); + if (!result) + { + return result; + } + // // Init Position Drawer ... eaPositionDrawer = new XCPositionDrawer(eaTrader); @@ -332,6 +361,10 @@ class XCBackTesterEA : public XCBase delete eaPositionDrawer; ZeroMemory(eaPositionDrawer); + // + delete eaVolume; + ZeroMemory(eaVolume); + // delete eaTrader; ZeroMemory(eaTrader); @@ -588,6 +621,15 @@ class XCBackTesterEA : public XCBase */ void HandleOnSignalTriggered(XSignal &signal) { + // + // 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( @@ -854,10 +896,6 @@ class XCBackTesterEA : public XCBase ulong chartId = ChartID(); objSuffix = eaLogSuffix + "_"; - // - // Initial Chart Class Instance ... - eaChartHelper = new XCChartHelper(chartId); - // int startX = 5; int startY = 25; diff --git a/Experts/x-saherelm.xfima.backtester.ea.mq5 b/Experts/x-saherelm.xfima.backtester.ea.mq5 index c9db4616..3eb0a53f 100644 --- a/Experts/x-saherelm.xfima.backtester.ea.mq5 +++ b/Experts/x-saherelm.xfima.backtester.ea.mq5 @@ -40,6 +40,17 @@ input long eaMagicNumber = 78692110; // Magic Number input int eaSlippage = 10; // Slippgae input string eaLogSuffix = ""; // Log Suffix +// +// 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 ... // Here we Provider All Requirements for @@ -232,6 +243,16 @@ int OnInit() eaExpert.eaSlippage = eaSlippage; eaExpert.eaLogSuffix = eaTag; + // + // 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; diff --git a/Libraries/x-saherelm.x-ohcl.lib.mq5 b/Libraries/x-saherelm.x-ohcl.lib.mq5 index 88730407..2b7e5319 100644 --- a/Libraries/x-saherelm.x-ohcl.lib.mq5 +++ b/Libraries/x-saherelm.x-ohcl.lib.mq5 @@ -758,6 +758,39 @@ struct XOHCL 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, diff --git a/Libraries/x-saherelm.x-pivot.analysis.lib.mq5 b/Libraries/x-saherelm.x-pivot.analysis.lib.mq5 index 829aa067..968a9c39 100644 --- a/Libraries/x-saherelm.x-pivot.analysis.lib.mq5 +++ b/Libraries/x-saherelm.x-pivot.analysis.lib.mq5 @@ -1378,7 +1378,7 @@ struct XPatternAnalysis for (int i = 0; i < count; i++) { // - has = forDir = patternsDir[i]; + has = forDir == patternsDir[i]; if (has) { result++; diff --git a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 index 75b5d8d2..e742ef33 100644 --- a/Libraries/x-saherelm.x-poi.extensions.lib.mq5 +++ b/Libraries/x-saherelm.x-poi.extensions.lib.mq5 @@ -4955,6 +4955,86 @@ bool HasInside( return result; } +/** + * 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 ... * diff --git a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 index abd41f8d..c248d5ff 100644 --- a/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 +++ b/XFIMAEA/Classes/x-saherelm.xfima.signaller.class.mq5 @@ -284,7 +284,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // // Ignore Signal Targets ... - ignoreTargets = true; + ignoreTargets = false; } // @@ -331,9 +331,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller string iName = NULL; bool isBullish = false; bool isBearish = false; - XPatternAnalysis iBarAnalysis; XFIMAConditions iFIMAConditions; - XFIMAMarketStructure iStructure; ENUM_X_DIRECTION iDir = X_DIRECTION_NONE; // @@ -380,22 +378,35 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller structureDrawConfig // ); + // // + // // Testing Porposes ... + // has = fimaHelper.IsBoundaryFakeBreaked( + // iDir, + // barIndex, + // X_PRICE_CLOSE, + // X_PRICE_CLOSE // + // ); + // if (has) + // { + // Print("Faked Break ..."); + // } + // // Disable Signallers ... - has = false; - iDir = X_DIRECTION_NONE; + // has = false; + // iDir = X_DIRECTION_NONE; // // Strategy 1 ... // Works on Support or Resistances Areas ... - // has = Strategy1HasSignal( - // iBar, - // iZone, - // iTargets, - // iDir, - // iFIMAConditions, - // iStructure // - // ); + has = Strategy1HasSignal( + iBar, + iZone, + iTargets, + iDir, + iFIMAConditions, + structure // + ); // // Strategy 2 ... @@ -409,7 +420,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller // iTargets, // iDir, // iFIMAConditions, - // iStructure // + // structure // // ); } @@ -462,8 +473,6 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller iBar.Clean(); iZone.Clean(); iSignal.Clean(); - iStructure.Clean(); - iBarAnalysis.Clean(); iFIMAConditions.Clean(); SpecifiedClean(iTargets); } @@ -543,6 +552,180 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller return result; } + // + // Testing Porposes ... + result = fimaHelper.IsBoundaryFakeBreaked( + dir, + bar.Index(), + X_PRICE_CLOSE, + X_PRICE_CLOSE // + ); + + // + // Nearest Noisy ZG Pivot Must has Same Direction + // by Boundary Faked Break ... + result = + result && + HasDirection(dir) && + _structure.zgAnalysis.IsValid() && + _structure.zgAnalysis.HasPivots() && + _structure.zgAnalysis.pivots[0].dir == dir; + + // + // We Have to Detect a Zone which Nearest ZG Pivot Reject or goes inside it ... + + // + int idx = -1; + XOHCL tmpBar; + XPivot pivot; + XPivot pivots[]; + XBoxZone zones[]; + bool has = false; + int zonesCount = 0; + int pivotIndex = -1; + XBoxZone affectedZone; + double bullishScore = 0; + double bearishScore = 0; + int prevPivotIndex = -1; + XBoxZone affectedZones[]; + int affectedZonesCount = 0; + + // + Copy( + _structure.zgAnalysis.pivots, + pivots // + ); + pivot = pivots[0]; + ArrayRemove(pivots, 0, 1); + + // + bool isBullish = IsXBullish(dir); + bool isBearish = IsXBearish(dir); + + // + zonesCount = _structure.CollectZones( + zones, + dir // + ); + result = result && + IsValidSize(zonesCount); + + // + // Noisey ZG Pivot must inside atleast one of Zones ... + + // + // Initial Pivots Bar ... + result = + result && + bar.BarAt(pivot.time, tmpBar); + + // + // Extract Affected Zones ... + if (result) + { + // + affectedZonesCount = ExtractAffectedZones( + tmpBar, + zones, + affectedZones, + dir // + ); + } + + // + // Validate Affected Zones ... + result = + result && + HasChild(affectedZones) && + affectedZonesCount >= 1; + if (result) + { + affectedZone = affectedZones[0]; + } + result = + result && + affectedZone.IsValid() && + (isBullish + ? bar.close > affectedZone.upper + : bar.close < affectedZone.lower); + + // + // There Must another Same Directional ZG Pivot Exists + // which is Affect another Zone ... + idx = GetYoungest(pivots, pivot.type); + result = + result && + IsValidIndex(idx) && + affectedZone.IsValid() && + (isBullish + ? pivots[idx].value < pivot.value + : pivots[idx].value > pivot.value); + if (result) + { + // + pivot.Clean(); + tmpBar.Clean(); + pivot = pivots[idx]; + XClean(affectedZones); + ArrayRemove(pivots, idx, 1); + + // + result = bar.BarAt(pivot.time, tmpBar); + } + + // + // Extract Affected Zones ... + XClean(affectedZones); + affectedZonesCount = 0; + if (result) + { + // + affectedZonesCount = ExtractAffectedZones( + tmpBar, + zones, + affectedZones, + dir // + ); + } + result = + result && + HasChild(affectedZones) && + affectedZonesCount >= 1; + + // + // Handling Scores ... + if (result) + { + // + for (int i = 0; i < ArraySize(_structure.barsAnalysis); i++) + { + // + bullishScore += _structure.barsAnalysis[i].Count(X_DIRECTION_BULLISH); + bearishScore += _structure.barsAnalysis[i].Count(X_DIRECTION_BEARISH); + } + } + result = + isBullish + ? bullishScore > bearishScore + : bearishScore > bullishScore; + + if (!result) + { + // + dir = X_DIRECTION_NONE; + + // + return result; + } + + // + // Validating ... + // Print("Validate ZG ..."); + + // // + // dir = X_DIRECTION_NONE; + // result = false; + // // Prepare zone ... if (result) @@ -554,12 +737,43 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller bar.period, bar.Index() + 2 // ); + zone.dir = dir; zone.symbol = bar.symbol; zone.period = bar.period; - // zone.dir = structure.maCrossDir; - zone.lower = bar.FindLowest(2, MODE_LOW); - zone.upper = bar.FindHighest(2, MODE_HIGH); - // zone.type = name + "_" + ToXString(structure.maCrossDir); + zone.type = name + "_" + ToXString(dir); + // zone.lower = bar.FindLowest(2, MODE_LOW); + // zone.upper = bar.FindHighest(2, MODE_HIGH); + double entry = GetEntry(bar.symbol, dir); + double points = GetPoints(bar.symbol); + zone.lower = entry - (100 * points); + zone.upper = entry + (100 * points); + + // + double tp1 = isBullish + ? entry + (100 * points) + : entry - (100 * points); + XTarget target1; + target1.target = tp1; + target1.doRF = true; + target1.actingDistance = 10; + + double tp2 = isBullish + ? entry + (200 * points) + : entry - (200 * points); + XTarget target2; + target2.target = tp2; + target2.doRF = true; + target2.actingDistance = 10; + + // + // AddRef( + // target1, + // targets // + // ); + AddRef( + target2, + targets // + ); // result = zone.IsValid(); @@ -577,7 +791,7 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller } // - // Cleanup Resources ... + // Cleanup ... if (!result) { // @@ -585,6 +799,14 @@ class XCXFIMAStrategy1Signaller : public XCXFIMABaseSignaller XClean(targets); } + // + pivot.Clean(); + XClean(zones); + tmpBar.Clean(); + XClean(pivots); + affectedZone.Clean(); + XClean(affectedZones); + // return result; } diff --git a/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 b/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 index 1650a2f9..51debf5d 100644 --- a/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 +++ b/XFIMAEA/Libraries/x-saherelm.xfima.lib.mq5 @@ -89,6 +89,223 @@ struct XFIMAMarketStructure return result; } + // + // Collectors ... + + /** + * Collect Required Zones from Structure ... + * + * @param dest: XBoxZone, reference collection to holds result ... + * @param forDir: ENUM_X_DIRECTION, Specified Collectiong ones Direction ... + * @param containsOB: bool, Contains OB Zones ... + * @param containsFVG: bool, Contains FVG Zones ... + * + * @return ( int ) + */ + int CollectZones( + XBoxZone &dest[], + ENUM_X_DIRECTION forDir = X_DIRECTION_NONE, + bool containsOB = false, + bool containsFVG = false // + ) + { + // + int result = 0; + + // + // Prepare ... + XClean(dest); + + // + // Validate ... + bool has = IsValid(); + if (!has) + { + return result; + } + + // + bool canCollectBullish = + IsXBullish(forDir) || + !HasDirection(forDir); + + // + bool canCollectBearish = + IsXBearish(forDir) || + !HasDirection(forDir); + + // + int count = 0; + XBoxZone tmpBox; + + // + // Check Analysis ... + + // + // XPV ... + has = pvAnalysis.IsValid(); + if (has) + { + // + // Support ... + tmpBox.Clean(); + has = pvAnalysis.HasSupportBox(tmpBox); + if (has && canCollectBullish) + { + // + AddIfNotExists( + tmpBox, + dest // + ); + } + + // + // Resistance ... + tmpBox.Clean(); + has = pvAnalysis.HasResistanceBox(tmpBox); + if (has && canCollectBearish) + { + // + AddIfNotExists( + tmpBox, + dest // + ); + } + } + + // + // XZG ... + has = zgAnalysis.IsValid(); + if (has) + { + // + // Support ... + tmpBox.Clean(); + has = zgAnalysis.HasSupportBox(tmpBox); + if (has && canCollectBullish) + { + // + AddIfNotExists( + tmpBox, + dest // + ); + } + + // + // Resistance ... + tmpBox.Clean(); + has = zgAnalysis.HasResistanceBox(tmpBox); + if (has && canCollectBearish) + { + // + AddIfNotExists( + tmpBox, + dest // + ); + } + } + + // + // Bar Patterns ... + has = HasChild(barsAnalysis); + if (has) + { + // + count = ArraySize(barsAnalysis); + for (int i = 0; i < count; i++) + { + // + // Support ... + has = barsAnalysis[i].IsSupport(); + if (has && canCollectBullish) + { + // + AddIfNotExists( + barsAnalysis[i].support, + dest // + ); + } + + // + // Resistance ... + has = barsAnalysis[i].IsResistance(); + if (has && canCollectBearish) + { + // + AddIfNotExists( + barsAnalysis[i].resistance, + dest // + ); + } + + // + // OB ... + if (containsOB) + { + // + has = barsAnalysis[i].IsOB(); + if (has) + { + // + has = (canCollectBullish && barsAnalysis[i].ob.IsBullish()) || + (canCollectBearish && barsAnalysis[i].ob.IsBearish()); + if (has) + { + // + AddIfNotExists( + barsAnalysis[i].ob, + dest // + ); + } + } + } + + // + // FVG ... + if (containsFVG) + { + has = barsAnalysis[i].IsFVG(); + if (has) + { + // + has = (canCollectBullish && barsAnalysis[i].fvg.IsBullish()) || + (canCollectBearish && barsAnalysis[i].fvg.IsBearish()); + if (has) + { + // + AddIfNotExists( + barsAnalysis[i].fvg, + dest // + ); + } + } + } + } + } + + // + result = ArraySize(dest); + has = IsValidSize(result); + if (has) + { + // + // Update To Time ... + // and also we Can Validate Zones Here ... + datetime cTime = TimeCurrent(); + for (int i = 0; i < result; i++) + { + dest[i].to = cTime; + } + } + + // + // Cleanup ... + tmpBox.Clean(); + + // + return result; + } + // }; @@ -281,12 +498,10 @@ struct XFIMAMarketStructureDrawerConfig XClean(barAnalysisDrawConfig.allowedDrawZones); Add( X_BAR_PATTERN_SUPPORT, - barAnalysisDrawConfig.allowedDrawZones - ); + barAnalysisDrawConfig.allowedDrawZones); Add( X_BAR_PATTERN_RESISTANCE, - barAnalysisDrawConfig.allowedDrawZones - ); + barAnalysisDrawConfig.allowedDrawZones); } /**