From 8cc1ca21dab9f41923184e631cbc28dece6eb232 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Mon, 6 Oct 2025 18:56:20 +0330 Subject: [PATCH] last works on Position Drawer Class and Implement it on EA Backtester Expert Class ... required to Test it's work ... --- .../x-saherelm.x-backtester.expert.class.mq5 | 38 +++- Classes/x-saherelm.x-cobject.class.mq5 | 27 +++ .../x-saherelm.x-position.drawer.class.mq5 | 186 +++++++++++++++++- 3 files changed, 240 insertions(+), 11 deletions(-) diff --git a/Classes/x-saherelm.x-backtester.expert.class.mq5 b/Classes/x-saherelm.x-backtester.expert.class.mq5 index eba97229..d773d788 100644 --- a/Classes/x-saherelm.x-backtester.expert.class.mq5 +++ b/Classes/x-saherelm.x-backtester.expert.class.mq5 @@ -24,6 +24,7 @@ #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" @@ -82,9 +83,10 @@ class XCBackTesterEA : public XCBase double volume; // Default volume Per Trade ... // - XCAlert *eaAlert; // EA Scope Alert Handler ... - XCTrade *eaTrader; // EA Scope Trade Handler ... - XCTarget *eaTarget; // EA Scope Target Manager ... + XCAlert *eaAlert; // EA Scope Alert Handler ... + XCTrade *eaTrader; // EA Scope Trade Handler ... + XCTarget *eaTarget; // EA Scope Target Manager ... + XCPositionDrawer *eaPositionDrawer; // EA Scope Position Drawer ... // XCChartHelper *eaChartHelper; // Chart Helper Class ... @@ -295,6 +297,10 @@ class XCBackTesterEA : public XCBase // Init Target Managers ... eaTarget = new XCTarget(eaTrader, eaAlert); + // + // Init Position Drawer ... + eaPositionDrawer = new XCPositionDrawer(eaTrader); + // // Initial GUI ... result = InitGUI(); @@ -321,6 +327,11 @@ class XCBackTesterEA : public XCBase delete eaTarget; ZeroMemory(eaTarget); + // + eaPositionDrawer.Destroy(); + delete eaPositionDrawer; + ZeroMemory(eaPositionDrawer); + // delete eaTrader; ZeroMemory(eaTrader); @@ -359,6 +370,10 @@ class XCBackTesterEA : public XCBase // // Managing Targets ... eaTarget.Manage(); + + // + // Manage Positions Drawings ... + eaPositionDrawer.Update(); } /** @@ -430,6 +445,9 @@ class XCBackTesterEA : public XCBase // eaTarget.HandleOnStopLossTriggered(deal); + + // + eaPositionDrawer.HandleStopLossTriggered(deal); } /** @@ -445,6 +463,9 @@ class XCBackTesterEA : public XCBase // eaTarget.HandleOnTakeProfitTriggered(deal); + + // + eaPositionDrawer.HandleOnTakeProfitTriggered(deal); } /** @@ -470,6 +491,13 @@ class XCBackTesterEA : public XCBase position, comment // ); + + // + eaPositionDrawer.HandleOnPositionForceClosed( + ticket, + position, + comment // + ); } /** @@ -572,7 +600,11 @@ class XCBackTesterEA : public XCBase */ void HandleOnSignalExecuted(XSignal &signal) { + // eaTarget.AddExecutedSignal(signal); + + // + eaPositionDrawer.AddExecutedSignal(signal); } // diff --git a/Classes/x-saherelm.x-cobject.class.mq5 b/Classes/x-saherelm.x-cobject.class.mq5 index 4bc8ef4c..eeeeab03 100644 --- a/Classes/x-saherelm.x-cobject.class.mq5 +++ b/Classes/x-saherelm.x-cobject.class.mq5 @@ -1945,6 +1945,33 @@ class XCPositionObject : public XCBaseObject 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 ... diff --git a/Classes/x-saherelm.x-position.drawer.class.mq5 b/Classes/x-saherelm.x-position.drawer.class.mq5 index bc955418..c63a7136 100644 --- a/Classes/x-saherelm.x-position.drawer.class.mq5 +++ b/Classes/x-saherelm.x-position.drawer.class.mq5 @@ -40,18 +40,25 @@ class XCPositionDrawer : public XCBase public: // // Props ... + int window; + ulong chartID; XCTrade *trader; CArrayObj positionObjects; + CArrayObj finalizedObjects; // // Constructor ... XCPositionDrawer( - XCTrade *_trader // + XCTrade *_trader, + ulong _chartID = 0, + int _window = 0 // ) : XCBase() { // Init( - _trader // + _trader, + _chartID, + _window // ); } @@ -66,12 +73,17 @@ class XCPositionDrawer : public XCBase // Tools ... void Init( - XCTrade *_trader // + XCTrade *_trader, + ulong _chartID = 0, + int _window = 0 // ) { // // Validate ... - bool has = _trader != NULL; + bool has = + _window >= 0 && + _chartID >= 0 && + _trader != NULL; if (!has) { return; @@ -79,6 +91,8 @@ class XCPositionDrawer : public XCBase // trader = _trader; + window = _window; + chartID = _chartID; } void Destroy() @@ -107,12 +121,66 @@ class XCPositionDrawer : public XCBase // // Validate ... bool has = IsValid(); - if (!has) { + 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) + { + ((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 ... + ((XCPositionObject *)positionObjects.At(i)).Update(barIndex); + } + } + + // + iPosition.Clean(); + } } // @@ -127,10 +195,52 @@ class XCPositionDrawer : public XCBase { // // Validate ... - if (!signal.IsValid() || !signal.IsExecuted()) + 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; + has = iObj.Create( + chartID, + window, + iPosition // + ); + } + + // + // Cleanup Resources ... + iPosition.Clean(); } /** @@ -138,8 +248,9 @@ class XCPositionDrawer : public XCBase * * @param deal: XDeal instance refrence, provides Triggered Deal info ... */ - void HandleOnStopLossTriggered(const XDeal &deal) + void HandleStopLossTriggered(const XDeal &deal) { + Finalize(deal.positionId); } /** @@ -149,6 +260,7 @@ class XCPositionDrawer : public XCBase */ void HandleOnTakeProfitTriggered(const XDeal &deal) { + Finalize(deal.positionId); } /** @@ -164,6 +276,7 @@ class XCPositionDrawer : public XCBase const string comment // ) { + Finalize(ticket); } // @@ -171,6 +284,63 @@ class XCPositionDrawer : public XCBase protected: // + // + 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); + } + + 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: